Explorar el Código

1.2 版本 界面优化 与 BUG修复

1. 修复节点信息获取错误的问题
2. 优化首页公告显示
3. 修复回复工单时按回车导致报错的问题
4. 修改用户编辑与添加排版
5. 修复潜在的IE兼容问题
6. 统一Table元素格式
7. 优化返利界面
8. 添加了封禁时间倒计时
9. 对非付费用户,首页添加提示购买宣传语
Bretton hace 5 años
padre
commit
66b0f7a561
Se han modificado 100 ficheros con 7488 adiciones y 8027 borrados
  1. 235 233
      app/Components/AlipayNotify.php
  2. 253 252
      app/Components/AlipaySubmit.php
  3. 21 21
      app/Components/CaptchaVerify.php
  4. 22 22
      app/Components/Curl.php
  5. 176 176
      app/Components/Helpers.php
  6. 14 14
      app/Components/IPIP.php
  7. 97 96
      app/Components/Namesilo.php
  8. 12 12
      app/Components/QQWry.php
  9. 50 49
      app/Components/ServerChan.php
  10. 65 63
      app/Components/Yzy.php
  11. 188 187
      app/Console/Commands/AutoCheckNodeTCP.php
  12. 48 48
      app/Console/Commands/AutoClearLog.php
  13. 113 112
      app/Console/Commands/AutoDecGoodsTraffic.php
  14. 594 593
      app/Console/Commands/AutoJob.php
  15. 41 41
      app/Console/Commands/AutoReportNode.php
  16. 59 59
      app/Console/Commands/AutoResetUserTraffic.php
  17. 46 46
      app/Console/Commands/AutoStatisticsNodeDailyTraffic.php
  18. 46 46
      app/Console/Commands/AutoStatisticsNodeHourlyTraffic.php
  19. 47 47
      app/Console/Commands/AutoStatisticsUserDailyTraffic.php
  20. 48 48
      app/Console/Commands/AutoStatisticsUserHourlyTraffic.php
  21. 45 45
      app/Console/Commands/UserExpireAutoWarning.php
  22. 46 46
      app/Console/Commands/UserTrafficAbnormalAutoWarning.php
  23. 47 47
      app/Console/Commands/UserTrafficAutoWarning.php
  24. 43 42
      app/Console/Commands/upgradeUserLabels.php
  25. 19 19
      app/Console/Commands/upgradeUserPassword.php
  26. 25 25
      app/Console/Commands/upgradeUserSpeedLimit.php
  27. 29 29
      app/Console/Commands/upgradeUserSubscribe.php
  28. 20 19
      app/Console/Commands/upgradeUserVmessId.php
  29. 76 58
      app/Console/Kernel.php
  30. 21 23
      app/Events/Event.php
  31. 95 92
      app/Exceptions/Handler.php
  32. 0 633
      app/Http/Controllers/AdminController.php
  33. 249 247
      app/Http/Controllers/Api/AlipayController.php
  34. 268 266
      app/Http/Controllers/Api/F2fpayController.php
  35. 125 124
      app/Http/Controllers/Api/LoginController.php
  36. 57 56
      app/Http/Controllers/Api/PingController.php
  37. 362 361
      app/Http/Controllers/Api/YzyController.php
  38. 727 727
      app/Http/Controllers/AuthController.php
  39. 152 151
      app/Http/Controllers/Controller.php
  40. 145 145
      app/Http/Controllers/CouponController.php
  41. 64 64
      app/Http/Controllers/MarketingController.php
  42. 228 228
      app/Http/Controllers/PaymentController.php
  43. 42 42
      app/Http/Controllers/SensitiveWordsController.php
  44. 213 213
      app/Http/Controllers/ShopController.php
  45. 257 257
      app/Http/Controllers/SubscribeController.php
  46. 104 104
      app/Http/Controllers/TicketController.php
  47. 856 871
      app/Http/Controllers/UserController.php
  48. 81 57
      app/Http/Kernel.php
  49. 18 17
      app/Http/Middleware/Affiliate.php
  50. 8 8
      app/Http/Middleware/CheckForMaintenanceMode.php
  51. 8 8
      app/Http/Middleware/EncryptCookies.php
  52. 17 16
      app/Http/Middleware/RedirectIfAuthenticated.php
  53. 20 19
      app/Http/Middleware/SetLocale.php
  54. 9 9
      app/Http/Middleware/TrimStrings.php
  55. 13 13
      app/Http/Middleware/TrustProxies.php
  56. 9 9
      app/Http/Middleware/VerifyCsrfToken.php
  57. 16 15
      app/Http/Middleware/isAdmin.php
  58. 73 72
      app/Http/Middleware/isForbidden.php
  59. 16 15
      app/Http/Middleware/isLogin.php
  60. 6 6
      app/Http/Middleware/isSecurity.php
  61. 11 10
      app/Http/Models/Article.php
  62. 5 4
      app/Http/Models/Config.php
  63. 5 4
      app/Http/Models/Country.php
  64. 33 32
      app/Http/Models/Coupon.php
  65. 4 3
      app/Http/Models/CouponLog.php
  66. 43 42
      app/Http/Models/Device.php
  67. 4 3
      app/Http/Models/EmailLog.php
  68. 33 32
      app/Http/Models/Goods.php
  69. 9 8
      app/Http/Models/GoodsLabel.php
  70. 22 21
      app/Http/Models/Invite.php
  71. 5 4
      app/Http/Models/Label.php
  72. 5 4
      app/Http/Models/Level.php
  73. 21 20
      app/Http/Models/Marketing.php
  74. 59 58
      app/Http/Models/Order.php
  75. 34 33
      app/Http/Models/OrderGoods.php
  76. 54 53
      app/Http/Models/Payment.php
  77. 24 23
      app/Http/Models/PaymentCallback.php
  78. 44 43
      app/Http/Models/ReferralApply.php
  79. 44 43
      app/Http/Models/ReferralLog.php
  80. 5 4
      app/Http/Models/SensitiveWords.php
  81. 15 14
      app/Http/Models/SsConfig.php
  82. 4 3
      app/Http/Models/SsGroup.php
  83. 5 4
      app/Http/Models/SsGroupNode.php
  84. 8 7
      app/Http/Models/SsNode.php
  85. 5 4
      app/Http/Models/SsNodeInfo.php
  86. 12 11
      app/Http/Models/SsNodeIp.php
  87. 10 9
      app/Http/Models/SsNodeLabel.php
  88. 5 4
      app/Http/Models/SsNodeOnlineLog.php
  89. 8 7
      app/Http/Models/SsNodeTrafficDaily.php
  90. 8 7
      app/Http/Models/SsNodeTrafficHourly.php
  91. 12 11
      app/Http/Models/Ticket.php
  92. 8 7
      app/Http/Models/TicketReply.php
  93. 46 45
      app/Http/Models/User.php
  94. 40 39
      app/Http/Models/UserBalanceLog.php
  95. 8 7
      app/Http/Models/UserBanLog.php
  96. 13 12
      app/Http/Models/UserLabel.php
  97. 8 7
      app/Http/Models/UserLoginLog.php
  98. 12 11
      app/Http/Models/UserSubscribe.php
  99. 5 4
      app/Http/Models/UserSubscribeLog.php
  100. 8 7
      app/Http/Models/UserTrafficDaily.php

+ 235 - 233
app/Components/AlipayNotify.php

@@ -2,6 +2,8 @@
 
 namespace App\Components;
 
+use Log;
+
 /**
  * Class AlipayNotify
  *
@@ -11,239 +13,239 @@ namespace App\Components;
  */
 class AlipayNotify
 {
-    private $https_verify_url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&'; // HTTPS形式消息验证地址
-    private $http_verify_url = 'http://notify.alipay.com/trade/notify_query.do?'; // HTTP形式消息验证地址
-    private $sign_type = "MD5"; // 加密方式:MD5/RSA
-    private $partner = "";
-    private $md5_key = "";
-    private $private_key = "";
-    private $alipay_public_key = "";
-    private $transport = "http";
-
-    function __construct($sign_type, $partner, $md5_key, $private_key, $alipay_public_key, $transport)
-    {
-        $this->sign_type = $sign_type;
-        $this->partner = $partner;
-        $this->md5_key = $md5_key;
-        $this->private_key = $private_key;
-        $this->alipay_public_key = $alipay_public_key;
-        $this->transport = $transport;
-    }
-
-    /**
-     * 针对notify_url验证消息是否是支付宝发出的合法消息
-     *
-     * @return bool 验证结果
-     */
-    public function verifyNotify()
-    {
-        if (empty($_POST)) {
-            return false;
-        } else {
-            // 生成签名结果
-            $isSign = $this->getSignVeryfy($_POST, $_POST["sign"]);
-
-            $converted_res = ($isSign) ? 'true' : 'false';
-
-            // 获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
-            $responseTxt = 'false';
-            if (!empty($_POST["notify_id"])) {
-                $responseTxt = $this->getResponse($_POST["notify_id"]);
-            }
-
-            // 验证
-            // $responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
-            // isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
-            if (preg_match("/true$/i", $responseTxt) && $isSign) {
-                return true;
-            } else {
-                return false;
-            }
-        }
-    }
-
-    /**
-     * 获取返回时的签名验证结果
-     *
-     * @param array  $para_temp 通知返回来的参数数组
-     * @param string $sign      返回的签名结果
-     *
-     * @return bool 签名验证结果
-     */
-    function getSignVeryfy($para_temp, $sign)
-    {
-        // 除去待签名参数数组中的空值和签名参数
-        $para_filter = $this->paraFilter($para_temp);
-
-        // 对待签名参数数组排序
-        $para_sort = $this->argSort($para_filter);
-
-        // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
-        $prestr = $this->createLinkString($para_sort);
-
-        switch (strtoupper(trim($this->sign_type))) {
-            case "RSA" :
-                $isSgin = $this->rsaVerify($prestr, trim($this->alipay_public_key), $sign);
-                break;
-            case "MD5" :
-                $isSgin = $this->md5Verify($prestr, $sign, trim($this->md5_key));
-                break;
-            default :
-                $isSgin = false;
-        }
-
-        return $isSgin;
-    }
-
-    /**
-     * 获取远程服务器ATN结果,验证返回URL
-     *
-     * @param integer $notify_id 通知校验ID
-     *
-     * @return string 服务器ATN结果
-     * 验证结果集:
-     * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
-     * true 返回正确信息
-     * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
-     */
-    function getResponse($notify_id)
-    {
-        $transport = strtolower(trim($this->transport));
-        $partner = trim($this->partner);
-
-        $verify_url = $transport == 'https' ? $this->https_verify_url : $this->http_verify_url;
-        $verify_url = $verify_url . "partner=" . $partner . "&notify_id=" . $notify_id;
-        $responseTxt = $this->getHttpResponseGET($verify_url, base_path('ca/cacert_alipay.pem'));
-
-        return $responseTxt;
-    }
-
-    /**
-     * RSA验签
-     *
-     * @param string $data              待签名数据
-     * @param string $alipay_public_key 支付宝的公钥字符串
-     * @param string $sign              要校对的的签名结果
-     *
-     * @return bool
-     */
-    function rsaVerify($data, $alipay_public_key, $sign)
-    {
-        // 以下为了初始化私钥,保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
-        $alipay_public_key = str_replace("-----BEGIN PUBLIC KEY-----", "", $alipay_public_key);
-        $alipay_public_key = str_replace("-----END PUBLIC KEY-----", "", $alipay_public_key);
-        $alipay_public_key = str_replace("\n", "", $alipay_public_key);
-
-        $alipay_public_key = '-----BEGIN PUBLIC KEY-----' . PHP_EOL . wordwrap($alipay_public_key, 64, "\n", true) . PHP_EOL . '-----END PUBLIC KEY-----';
-        $res = openssl_get_publickey($alipay_public_key);
-        if (!$res) {
-            \Log::error("支付宝公钥格式不正确");
-            exit();
-        }
-
-        $result = (bool)openssl_verify($data, base64_decode($sign), $res);
-        openssl_free_key($res);
-
-        return $result;
-    }
-
-    /**
-     * 验证签名
-     *
-     * @param string $prestr 需要签名的字符串pre-sign
-     * @param string $sign   签名结果
-     * @param string $key    私钥
-     *
-     * @return bool
-     */
-    function md5Verify($prestr, $sign, $key)
-    {
-        $mysgin = md5($prestr . $key);
-
-        return $mysgin == $sign ? true : false;
-    }
-
-    /**
-     * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
-     *
-     * @param array $para 需要拼接的数组
-     *
-     * @return string
-     */
-    function createLinkString($para)
-    {
-        $arg = "";
-        while (list ($key, $val) = each($para)) {
-            $arg .= $key . "=" . $val . "&";
-        }
-
-        // 去掉最后一个&字符
-        $arg = substr($arg, 0, count($arg) - 2);
-
-        // 如果存在转义字符,那么去掉转义
-        if (get_magic_quotes_gpc()) {
-            $arg = stripslashes($arg);
-        }
-
-        return $arg;
-    }
-
-    /**
-     * 远程获取数据,GET模式
-     * 注意:文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
-     *
-     * @param string $url        指定URL完整路径地址
-     * @param string $cacert_url 指定当前工作目录绝对路径
-     *
-     * @return mixed
-     */
-    function getHttpResponseGET($url, $cacert_url)
-    {
-        $curl = curl_init($url);
-        curl_setopt($curl, CURLOPT_HEADER, 0); // 过滤HTTP头
-        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 显示输出结果
-        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, true); // SSL证书认证
-        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); // 严格认证
-        curl_setopt($curl, CURLOPT_CAINFO, $cacert_url); // 证书地址
-        $responseText = curl_exec($curl);
-        //var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
-        curl_close($curl);
-
-        return $responseText;
-    }
-
-    /**
-     * 除去数组中的空值和签名参数
-     *
-     * @param array $para 签名参数组
-     *
-     * @return array 去掉空值与签名参数后的新签名参数组
-     */
-    function paraFilter($para)
-    {
-        $para_filter = [];
-        while (list ($key, $val) = each($para)) {
-            if ($key == "sign" || $key == "sign_type" || $val == "") continue;
-            else    $para_filter[$key] = $para[$key];
-        }
-
-        return $para_filter;
-    }
-
-    /**
-     * 对数组排序
-     *
-     * @param array $para 排序前的数组
-     *
-     * @return array 排序后的数组
-     */
-    function argSort($para)
-    {
-        ksort($para);
-        reset($para);
-
-        return $para;
-    }
+	private $https_verify_url = 'https://mapi.alipay.com/gateway.do?service=notify_verify&'; // HTTPS形式消息验证地址
+	private $http_verify_url = 'http://notify.alipay.com/trade/notify_query.do?'; // HTTP形式消息验证地址
+	private $sign_type = "MD5"; // 加密方式:MD5/RSA
+	private $partner = "";
+	private $md5_key = "";
+	private $private_key = "";
+	private $alipay_public_key = "";
+	private $transport = "http";
+
+	function __construct($sign_type, $partner, $md5_key, $private_key, $alipay_public_key, $transport)
+	{
+		$this->sign_type = $sign_type;
+		$this->partner = $partner;
+		$this->md5_key = $md5_key;
+		$this->private_key = $private_key;
+		$this->alipay_public_key = $alipay_public_key;
+		$this->transport = $transport;
+	}
+
+	/**
+	 * 针对notify_url验证消息是否是支付宝发出的合法消息
+	 *
+	 * @return bool 验证结果
+	 */
+	public function verifyNotify()
+	{
+		if(empty($_POST)){
+			return FALSE;
+		}else{
+			// 生成签名结果
+			$isSign = $this->getSignVeryfy($_POST, $_POST["sign"]);
+
+			$converted_res = ($isSign)? 'true' : 'false';
+
+			// 获取支付宝远程服务器ATN结果(验证是否是支付宝发来的消息)
+			$responseTxt = 'false';
+			if(!empty($_POST["notify_id"])){
+				$responseTxt = $this->getResponse($_POST["notify_id"]);
+			}
+
+			// 验证
+			// $responsetTxt的结果不是true,与服务器设置问题、合作身份者ID、notify_id一分钟失效有关
+			// isSign的结果不是true,与安全校验码、请求时的参数格式(如:带自定义参数等)、编码格式有关
+			if(preg_match("/true$/i", $responseTxt) && $isSign){
+				return TRUE;
+			}else{
+				return FALSE;
+			}
+		}
+	}
+
+	/**
+	 * 获取返回时的签名验证结果
+	 *
+	 * @param array  $para_temp 通知返回来的参数数组
+	 * @param string $sign      返回的签名结果
+	 *
+	 * @return bool 签名验证结果
+	 */
+	function getSignVeryfy($para_temp, $sign)
+	{
+		// 除去待签名参数数组中的空值和签名参数
+		$para_filter = $this->paraFilter($para_temp);
+
+		// 对待签名参数数组排序
+		$para_sort = $this->argSort($para_filter);
+
+		// 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
+		$prestr = $this->createLinkString($para_sort);
+
+		switch(strtoupper(trim($this->sign_type))){
+			case "RSA" :
+				$isSgin = $this->rsaVerify($prestr, trim($this->alipay_public_key), $sign);
+				break;
+			case "MD5" :
+				$isSgin = $this->md5Verify($prestr, $sign, trim($this->md5_key));
+				break;
+			default :
+				$isSgin = FALSE;
+		}
+
+		return $isSgin;
+	}
+
+	/**
+	 * 获取远程服务器ATN结果,验证返回URL
+	 *
+	 * @param integer $notify_id 通知校验ID
+	 *
+	 * @return string 服务器ATN结果
+	 * 验证结果集:
+	 * invalid命令参数不对 出现这个错误,请检测返回处理中partner和key是否为空
+	 * true 返回正确信息
+	 * false 请检查防火墙或者是服务器阻止端口问题以及验证时间是否超过一分钟
+	 */
+	function getResponse($notify_id)
+	{
+		$transport = strtolower(trim($this->transport));
+		$partner = trim($this->partner);
+
+		$verify_url = $transport == 'https'? $this->https_verify_url : $this->http_verify_url;
+		$verify_url = $verify_url."partner=".$partner."&notify_id=".$notify_id;
+		$responseTxt = $this->getHttpResponseGET($verify_url, base_path('ca/cacert_alipay.pem'));
+
+		return $responseTxt;
+	}
+
+	/**
+	 * RSA验签
+	 *
+	 * @param string $data              待签名数据
+	 * @param string $alipay_public_key 支付宝的公钥字符串
+	 * @param string $sign              要校对的的签名结果
+	 *
+	 * @return bool
+	 */
+	function rsaVerify($data, $alipay_public_key, $sign)
+	{
+		// 以下为了初始化私钥,保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
+		$alipay_public_key = str_replace("-----BEGIN PUBLIC KEY-----", "", $alipay_public_key);
+		$alipay_public_key = str_replace("-----END PUBLIC KEY-----", "", $alipay_public_key);
+		$alipay_public_key = str_replace("\n", "", $alipay_public_key);
+
+		$alipay_public_key = '-----BEGIN PUBLIC KEY-----'.PHP_EOL.wordwrap($alipay_public_key, 64, "\n", TRUE).PHP_EOL.'-----END PUBLIC KEY-----';
+		$res = openssl_get_publickey($alipay_public_key);
+		if(!$res){
+			Log::error("支付宝公钥格式不正确");
+			exit();
+		}
+
+		$result = (bool)openssl_verify($data, base64_decode($sign), $res);
+		openssl_free_key($res);
+
+		return $result;
+	}
+
+	/**
+	 * 验证签名
+	 *
+	 * @param string $prestr 需要签名的字符串pre-sign
+	 * @param string $sign   签名结果
+	 * @param string $key    私钥
+	 *
+	 * @return bool
+	 */
+	function md5Verify($prestr, $sign, $key)
+	{
+		$mysgin = md5($prestr.$key);
+
+		return $mysgin == $sign? TRUE : FALSE;
+	}
+
+	/**
+	 * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
+	 *
+	 * @param array $para 需要拼接的数组
+	 *
+	 * @return string
+	 */
+	function createLinkString($para)
+	{
+		$arg = "";
+		while(list ($key, $val) = each($para)){
+			$arg .= $key."=".$val."&";
+		}
+
+		// 去掉最后一个&字符
+		$arg = substr($arg, 0, count($arg)-2);
+
+		// 如果存在转义字符,那么去掉转义
+		if(get_magic_quotes_gpc()){
+			$arg = stripslashes($arg);
+		}
+
+		return $arg;
+	}
+
+	/**
+	 * 远程获取数据,GET模式
+	 * 注意:文件夹中cacert.pem是SSL证书请保证其路径有效,目前默认路径是:getcwd().'\\cacert.pem'
+	 *
+	 * @param string $url        指定URL完整路径地址
+	 * @param string $cacert_url 指定当前工作目录绝对路径
+	 *
+	 * @return mixed
+	 */
+	function getHttpResponseGET($url, $cacert_url)
+	{
+		$curl = curl_init($url);
+		curl_setopt($curl, CURLOPT_HEADER, 0); // 过滤HTTP头
+		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 显示输出结果
+		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, TRUE); // SSL证书认证
+		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 2); // 严格认证
+		curl_setopt($curl, CURLOPT_CAINFO, $cacert_url); // 证书地址
+		$responseText = curl_exec($curl);
+		//var_dump( curl_error($curl) );//如果执行curl过程中出现异常,可打开此开关,以便查看异常内容
+		curl_close($curl);
+
+		return $responseText;
+	}
+
+	/**
+	 * 除去数组中的空值和签名参数
+	 *
+	 * @param array $para 签名参数组
+	 *
+	 * @return array 去掉空值与签名参数后的新签名参数组
+	 */
+	function paraFilter($para)
+	{
+		$para_filter = [];
+		while(list ($key, $val) = each($para)){
+			if($key == "sign" || $key == "sign_type" || $val == "") continue;
+			else    $para_filter[$key] = $para[$key];
+		}
+
+		return $para_filter;
+	}
+
+	/**
+	 * 对数组排序
+	 *
+	 * @param array $para 排序前的数组
+	 *
+	 * @return array 排序后的数组
+	 */
+	function argSort($para)
+	{
+		ksort($para);
+		reset($para);
+
+		return $para;
+	}
 }
 
 ?>

+ 253 - 252
app/Components/AlipaySubmit.php

@@ -2,7 +2,8 @@
 
 namespace App\Components;
 
-use \DOMDocument;
+use DOMDocument;
+use Log;
 
 /**
  * Class AlipaySubmit
@@ -13,255 +14,255 @@ use \DOMDocument;
  */
 class AlipaySubmit
 {
-    var $alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?'; // 支付宝网关地址(新)
-    var $sign_type = "MD5"; // 加密方式:MD5/RSA
-    var $partner = "";
-    var $md5_key = "";
-    var $private_key = "";
-
-    function __construct($sign_type, $partner, $md5_key, $private_key)
-    {
-        $this->sign_type = $sign_type;
-        $this->partner = $partner;
-        $this->md5_key = $md5_key;
-        $this->private_key = $private_key;
-    }
-
-    /**
-     * 生成签名结果
-     *
-     * @param array $para_sort 已排序要签名的数组
-     *
-     * @return string
-     */
-    function buildRequestMysign($para_sort)
-    {
-        // 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
-        $prestr = $this->createLinkString($para_sort);
-
-        switch (strtoupper(trim($this->sign_type))) {
-            case "MD5" :
-                $mysign = $this->md5Sign($prestr, $this->md5_key);
-                break;
-            case "RSA" :
-                $mysign = $this->rsaSign($prestr, $this->private_key);
-                break;
-            default :
-                $mysign = "";
-        }
-
-        return $mysign;
-    }
-
-    /**
-     * 生成要请求给支付宝的参数数组
-     *
-     * @param array $para_temp 请求前的参数数组
-     *
-     * @return array
-     */
-    function buildRequestPara($para_temp)
-    {
-        // 除去待签名参数数组中的空值和签名参数
-        $para_filter = $this->paraFilter($para_temp);
-
-        // 对待签名参数数组排序
-        $para_sort = $this->argSort($para_filter);
-
-        // 生成签名结果
-        $mysign = $this->buildRequestMysign($para_sort);
-
-        // 签名结果与签名方式加入请求提交参数组中
-        $para_sort['sign'] = $mysign;
-        $para_sort['sign_type'] = strtoupper(trim($this->sign_type));
-
-        return $para_sort;
-    }
-
-    /**
-     * 生成要请求给支付宝的参数数组
-     *
-     * @param array $para_temp 请求前的参数数组
-     *
-     * @return string
-     */
-    function buildRequestParaToString($para_temp)
-    {
-        // 待请求参数数组
-        $para = $this->buildRequestPara($para_temp);
-
-        // 把参数组中所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
-        $request_data = $this->createLinkStringUrlEncode($para);
-
-        return $request_data;
-    }
-
-    /**
-     * 建立请求,以表单HTML形式构造(默认)
-     *
-     * @param array  $para_temp   请求参数数组
-     * @param string $method      提交方式。两个值可选:post、get
-     * @param string $button_name 确认按钮显示文字
-     *
-     * @return string
-     */
-    public function buildRequestForm($para_temp, $method, $button_name)
-    {
-        // 待请求参数数组
-        $para = $this->buildRequestPara($para_temp);
-
-        $sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='" . $this->alipay_gateway_new . "_input_charset=utf-8' method='" . $method . "'>";
-        while (list ($key, $val) = each($para)) {
-            $sHtml .= "<input type='hidden' name='" . $key . "' value='" . $val . "'/>";
-        }
-
-        // submit按钮控件请不要含有name属性
-        $sHtml = $sHtml . "<input type='submit'  value='" . $button_name . "' style='display:none;'></form>";
-        $sHtml = $sHtml . "<script>document.forms['alipaysubmit'].submit();</script>";
-
-        return $sHtml;
-    }
-
-    /**
-     * 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
-     *
-     * @return string
-     */
-    function query_timestamp()
-    {
-        $url = $this->alipay_gateway_new . "service=query_timestamp&partner=" . trim(strtolower($this->partner)) . "&_input_charset=utf-8";
-
-        $doc = new DOMDocument();
-        $doc->load($url);
-        $itemEncrypt_key = $doc->getElementsByTagName("encrypt_key");
-        $encrypt_key = $itemEncrypt_key->item(0)->nodeValue;
-
-        return $encrypt_key;
-    }
-
-    /**
-     * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
-     *
-     * @param array $para
-     *
-     * @return bool|string
-     */
-    function createLinkString($para)
-    {
-        $arg = "";
-        while (list ($key, $val) = each($para)) {
-            $arg .= $key . "=" . $val . "&";
-        }
-
-        // 去掉最后一个&字符
-        $arg = substr($arg, 0, count($arg) - 2);
-
-        // 如果存在转义字符,那么去掉转义
-        if (get_magic_quotes_gpc()) {
-            $arg = stripslashes($arg);
-        }
-
-        return $arg;
-    }
-
-    /**
-     * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
-     *
-     * @param array $para 需要拼接的数组
-     *
-     * @return bool|string
-     */
-    function createLinkStringUrlEncode($para)
-    {
-        $arg = "";
-        while (list ($key, $val) = each($para)) {
-            $arg .= $key . "=" . urlencode($val) . "&";
-        }
-
-        // 去掉最后一个&字符
-        $arg = substr($arg, 0, count($arg) - 2);
-
-        // 如果存在转义字符,那么去掉转义
-        if (get_magic_quotes_gpc()) {
-            $arg = stripslashes($arg);
-        }
-
-        return $arg;
-    }
-
-    /**
-     * RSA签名
-     *
-     * @param string $data        待签名数据
-     * @param string $private_key 商户私钥字符串
-     *
-     * @return string
-     */
-    function rsaSign($data, $private_key)
-    {
-        //以下为了初始化私钥,保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
-        $private_key = str_replace("-----BEGIN RSA PRIVATE KEY-----", "", $private_key);
-        $private_key = str_replace("-----END RSA PRIVATE KEY-----", "", $private_key);
-        $private_key = str_replace("\n", "", $private_key);
-        $private_key = "-----BEGIN RSA PRIVATE KEY-----" . PHP_EOL . wordwrap($private_key, 64, "\n", true) . PHP_EOL . "-----END RSA PRIVATE KEY-----";
-
-        $res = openssl_get_privatekey($private_key);
-        if (!$res) {
-            \Log::error("私钥格式不正确");
-            exit();
-        }
-
-        openssl_sign($data, $sign, $res);
-        openssl_free_key($res);
-
-        $sign = base64_encode($sign); // base64编码
-
-        return $sign;
-    }
-
-    /**
-     * 签名字符串
-     *
-     * @param string $prestr 需要签名的字符串
-     * @param string $key    私钥
-     *
-     * @return string
-     */
-    function md5Sign($prestr, $key)
-    {
-        return md5($prestr . $key);
-    }
-
-    /**
-     * 除去数组中的空值和签名参数
-     *
-     * @param array $para 签名参数组
-     *
-     * @return array
-     */
-    function paraFilter($para)
-    {
-        $para_filter = [];
-        while (list ($key, $val) = each($para)) {
-            if ($key == "sign" || $key == "sign_type" || $val == "") continue;
-            else    $para_filter[$key] = $para[$key];
-        }
-
-        return $para_filter;
-    }
-
-    /**
-     * 对数组排序
-     *
-     * @param array $para 排序前的数组
-     *
-     * @return mixed
-     */
-    function argSort($para)
-    {
-        ksort($para);
-        reset($para);
-
-        return $para;
-    }
+	var $alipay_gateway_new = 'https://mapi.alipay.com/gateway.do?'; // 支付宝网关地址(新)
+	var $sign_type = "MD5"; // 加密方式:MD5/RSA
+	var $partner = "";
+	var $md5_key = "";
+	var $private_key = "";
+
+	function __construct($sign_type, $partner, $md5_key, $private_key)
+	{
+		$this->sign_type = $sign_type;
+		$this->partner = $partner;
+		$this->md5_key = $md5_key;
+		$this->private_key = $private_key;
+	}
+
+	/**
+	 * 生成签名结果
+	 *
+	 * @param array $para_sort 已排序要签名的数组
+	 *
+	 * @return string
+	 */
+	function buildRequestMysign($para_sort)
+	{
+		// 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
+		$prestr = $this->createLinkString($para_sort);
+
+		switch(strtoupper(trim($this->sign_type))){
+			case "MD5" :
+				$mysign = $this->md5Sign($prestr, $this->md5_key);
+				break;
+			case "RSA" :
+				$mysign = $this->rsaSign($prestr, $this->private_key);
+				break;
+			default :
+				$mysign = "";
+		}
+
+		return $mysign;
+	}
+
+	/**
+	 * 生成要请求给支付宝的参数数组
+	 *
+	 * @param array $para_temp 请求前的参数数组
+	 *
+	 * @return array
+	 */
+	function buildRequestPara($para_temp)
+	{
+		// 除去待签名参数数组中的空值和签名参数
+		$para_filter = $this->paraFilter($para_temp);
+
+		// 对待签名参数数组排序
+		$para_sort = $this->argSort($para_filter);
+
+		// 生成签名结果
+		$mysign = $this->buildRequestMysign($para_sort);
+
+		// 签名结果与签名方式加入请求提交参数组中
+		$para_sort['sign'] = $mysign;
+		$para_sort['sign_type'] = strtoupper(trim($this->sign_type));
+
+		return $para_sort;
+	}
+
+	/**
+	 * 生成要请求给支付宝的参数数组
+	 *
+	 * @param array $para_temp 请求前的参数数组
+	 *
+	 * @return string
+	 */
+	function buildRequestParaToString($para_temp)
+	{
+		// 待请求参数数组
+		$para = $this->buildRequestPara($para_temp);
+
+		// 把参数组中所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
+		$request_data = $this->createLinkStringUrlEncode($para);
+
+		return $request_data;
+	}
+
+	/**
+	 * 建立请求,以表单HTML形式构造(默认)
+	 *
+	 * @param array  $para_temp   请求参数数组
+	 * @param string $method      提交方式。两个值可选:post、get
+	 * @param string $button_name 确认按钮显示文字
+	 *
+	 * @return string
+	 */
+	public function buildRequestForm($para_temp, $method, $button_name)
+	{
+		// 待请求参数数组
+		$para = $this->buildRequestPara($para_temp);
+
+		$sHtml = "<form id='alipaysubmit' name='alipaysubmit' action='".$this->alipay_gateway_new."_input_charset=utf-8' method='".$method."'>";
+		while(list ($key, $val) = each($para)){
+			$sHtml .= "<input type='hidden' name='".$key."' value='".$val."'/>";
+		}
+
+		// submit按钮控件请不要含有name属性
+		$sHtml = $sHtml."<input type='submit'  value='".$button_name."' style='display:none;'></form>";
+		$sHtml = $sHtml."<script>document.forms['alipaysubmit'].submit();</script>";
+
+		return $sHtml;
+	}
+
+	/**
+	 * 用于防钓鱼,调用接口query_timestamp来获取时间戳的处理函数
+	 *
+	 * @return string
+	 */
+	function query_timestamp()
+	{
+		$url = $this->alipay_gateway_new."service=query_timestamp&partner=".trim(strtolower($this->partner))."&_input_charset=utf-8";
+
+		$doc = new DOMDocument();
+		$doc->load($url);
+		$itemEncrypt_key = $doc->getElementsByTagName("encrypt_key");
+		$encrypt_key = $itemEncrypt_key->item(0)->nodeValue;
+
+		return $encrypt_key;
+	}
+
+	/**
+	 * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串
+	 *
+	 * @param array $para
+	 *
+	 * @return bool|string
+	 */
+	function createLinkString($para)
+	{
+		$arg = "";
+		while(list ($key, $val) = each($para)){
+			$arg .= $key."=".$val."&";
+		}
+
+		// 去掉最后一个&字符
+		$arg = substr($arg, 0, count($arg)-2);
+
+		// 如果存在转义字符,那么去掉转义
+		if(get_magic_quotes_gpc()){
+			$arg = stripslashes($arg);
+		}
+
+		return $arg;
+	}
+
+	/**
+	 * 把数组所有元素,按照“参数=参数值”的模式用“&”字符拼接成字符串,并对字符串做urlencode编码
+	 *
+	 * @param array $para 需要拼接的数组
+	 *
+	 * @return bool|string
+	 */
+	function createLinkStringUrlEncode($para)
+	{
+		$arg = "";
+		while(list ($key, $val) = each($para)){
+			$arg .= $key."=".urlencode($val)."&";
+		}
+
+		// 去掉最后一个&字符
+		$arg = substr($arg, 0, count($arg)-2);
+
+		// 如果存在转义字符,那么去掉转义
+		if(get_magic_quotes_gpc()){
+			$arg = stripslashes($arg);
+		}
+
+		return $arg;
+	}
+
+	/**
+	 * RSA签名
+	 *
+	 * @param string $data        待签名数据
+	 * @param string $private_key 商户私钥字符串
+	 *
+	 * @return string
+	 */
+	function rsaSign($data, $private_key)
+	{
+		//以下为了初始化私钥,保证在您填写私钥时不管是带格式还是不带格式都可以通过验证。
+		$private_key = str_replace("-----BEGIN RSA PRIVATE KEY-----", "", $private_key);
+		$private_key = str_replace("-----END RSA PRIVATE KEY-----", "", $private_key);
+		$private_key = str_replace("\n", "", $private_key);
+		$private_key = "-----BEGIN RSA PRIVATE KEY-----".PHP_EOL.wordwrap($private_key, 64, "\n", TRUE).PHP_EOL."-----END RSA PRIVATE KEY-----";
+
+		$res = openssl_get_privatekey($private_key);
+		if(!$res){
+			Log::error("私钥格式不正确");
+			exit();
+		}
+
+		openssl_sign($data, $sign, $res);
+		openssl_free_key($res);
+
+		$sign = base64_encode($sign); // base64编码
+
+		return $sign;
+	}
+
+	/**
+	 * 签名字符串
+	 *
+	 * @param string $prestr 需要签名的字符串
+	 * @param string $key    私钥
+	 *
+	 * @return string
+	 */
+	function md5Sign($prestr, $key)
+	{
+		return md5($prestr.$key);
+	}
+
+	/**
+	 * 除去数组中的空值和签名参数
+	 *
+	 * @param array $para 签名参数组
+	 *
+	 * @return array
+	 */
+	function paraFilter($para)
+	{
+		$para_filter = [];
+		while(list ($key, $val) = each($para)){
+			if($key == "sign" || $key == "sign_type" || $val == "") continue;
+			else    $para_filter[$key] = $para[$key];
+		}
+
+		return $para_filter;
+	}
+
+	/**
+	 * 对数组排序
+	 *
+	 * @param array $para 排序前的数组
+	 *
+	 * @return mixed
+	 */
+	function argSort($para)
+	{
+		ksort($para);
+		reset($para);
+
+		return $para;
+	}
 }

+ 21 - 21
app/Components/CaptchaVerify.php

@@ -9,28 +9,28 @@ namespace App\Components;
  */
 Class CaptchaVerify
 {
-    /**
-     * 从后台获取 Geetest_id 和 Geetest_key
-     */
-    public static function geetestCaptchaGetConfig()
-    {
-        return [
-            "geetest_id"  => Helpers::systemConfig()["geetest_id"],
-            "geetest_key" => Helpers::systemConfig()["geetest_key"]
-        ];
-    }
+	/**
+	 * 从后台获取 Geetest_id 和 Geetest_key
+	 */
+	public static function geetestCaptchaGetConfig()
+	{
+		return [
+			"geetest_id"  => Helpers::systemConfig()["geetest_id"],
+			"geetest_key" => Helpers::systemConfig()["geetest_key"]
+		];
+	}
 
-    /**
-     * 从后台获取 google_captcha_sitekey 和 google_captcha_secret
-     */
-    public static function googleCaptchaGetConfig()
-    {
-        return [
-            "sitekey" => Helpers::systemConfig()["google_captcha_sitekey"],
-            "secret"  => Helpers::systemConfig()["google_captcha_secret"],
-            "options" => []
-        ];
-    }
+	/**
+	 * 从后台获取 google_captcha_sitekey 和 google_captcha_secret
+	 */
+	public static function googleCaptchaGetConfig()
+	{
+		return [
+			"sitekey" => Helpers::systemConfig()["google_captcha_sitekey"],
+			"secret"  => Helpers::systemConfig()["google_captcha_secret"],
+			"options" => []
+		];
+	}
 }
 
 ?>

+ 22 - 22
app/Components/Curl.php

@@ -4,29 +4,29 @@ namespace App\Components;
 
 class Curl
 {
-    /**
-     * @param string $url  请求地址
-     * @param array  $data 数据,如果有数据则用POST请求
-     *
-     * @return mixed
-     */
-    public static function send($url, $data = [])
-    {
-        $ch = curl_init();
-        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-        curl_setopt($ch, CURLOPT_TIMEOUT, 3);
-        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
-        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
-        curl_setopt($ch, CURLOPT_URL, $url);
+	/**
+	 * @param string $url  请求地址
+	 * @param array  $data 数据,如果有数据则用POST请求
+	 *
+	 * @return mixed
+	 */
+	public static function send($url, $data = [])
+	{
+		$ch = curl_init();
+		curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
+		curl_setopt($ch, CURLOPT_TIMEOUT, 3);
+		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
+		curl_setopt($ch, CURLOPT_URL, $url);
 
-        if ($data) {
-            curl_setopt($ch, CURLOPT_POST, 1);
-            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
-        }
+		if($data){
+			curl_setopt($ch, CURLOPT_POST, 1);
+			curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+		}
 
-        $res = curl_exec($ch);
-        curl_close($ch);
+		$res = curl_exec($ch);
+		curl_close($ch);
 
-        return $res;
-    }
+		return $res;
+	}
 }

+ 176 - 176
app/Components/Helpers.php

@@ -13,180 +13,180 @@ use App\Http\Models\UserTrafficModifyLog;
 
 class Helpers
 {
-    // 不生成的端口
-    private static $denyPorts = [
-        1068, 1109, 1434, 3127, 3128,
-        3129, 3130, 3332, 4444, 5554,
-        6669, 8080, 8081, 8082, 8181,
-        8282, 9996, 17185, 24554, 35601,
-        60177, 60179
-    ];
-
-    // 获取系统配置
-    public static function systemConfig()
-    {
-        $config = Config::query()->get();
-        $data = [];
-        foreach ($config as $vo) {
-            $data[$vo->name] = $vo->value;
-        }
-
-        return $data;
-    }
-
-    // 获取默认加密方式
-    public static function getDefaultMethod()
-    {
-        $config = SsConfig::default()->type(1)->first();
-
-        return $config ? $config->name : 'aes-256-cfb';
-    }
-
-    // 获取默认协议
-    public static function getDefaultProtocol()
-    {
-        $config = SsConfig::default()->type(2)->first();
-
-        return $config ? $config->name : 'origin';
-    }
-
-    // 获取默认混淆
-    public static function getDefaultObfs()
-    {
-        $config = SsConfig::default()->type(3)->first();
-
-        return $config ? $config->name : 'plain';
-    }
-
-    // 获取一个随机端口
-    public static function getRandPort()
-    {
-        $config = self::systemConfig();
-        $port = mt_rand($config['min_port'], $config['max_port']);
-
-        $exists_port = User::query()->pluck('port')->toArray();
-        if (in_array($port, $exists_port) || in_array($port, self::$denyPorts)) {
-            $port = self::getRandPort();
-        }
-
-        return $port;
-    }
-
-    // 获取一个端口
-    public static function getOnlyPort()
-    {
-        $config = self::systemConfig();
-        $port = $config['min_port'];
-
-        $exists_port = User::query()->where('port', '>=', $config['min_port'])->pluck('port')->toArray();
-        while (in_array($port, $exists_port) || in_array($port, self::$denyPorts)) {
-            $port = $port + 1;
-        }
-
-        return $port;
-    }
-
-    // 加密方式
-    public static function methodList()
-    {
-        return SsConfig::type(1)->get();
-    }
-
-    // 协议
-    public static function protocolList()
-    {
-        return SsConfig::type(2)->get();
-    }
-
-    // 混淆
-    public static function obfsList()
-    {
-        return SsConfig::type(3)->get();
-    }
-
-    // 等级
-    public static function levelList()
-    {
-        return Level::query()->get()->sortBy('level');
-    }
-
-    // 生成用户的订阅码
-    public static function makeSubscribeCode()
-    {
-        $code = makeRandStr(5);
-        if (UserSubscribe::query()->where('code', $code)->exists()) {
-            $code = self::makeSubscribeCode();
-        }
-
-        return $code;
-    }
-
-    /**
-     * 添加邮件投递日志
-     *
-     * @param string $address 收信地址
-     * @param string $title   标题
-     * @param string $content 内容
-     * @param int    $status  投递状态
-     * @param string $error   投递失败时记录的异常信息
-     *
-     * @return int
-     */
-    public static function addEmailLog($address, $title, $content, $status = 1, $error = '')
-    {
-        $log = new EmailLog();
-        $log->type = 1;
-        $log->address = $address;
-        $log->title = $title;
-        $log->content = $content;
-        $log->status = $status;
-        $log->error = $error;
-        $log->save();
-
-        return $log->id;
-    }
-
-    /**
-     * 添加优惠券操作日志
-     *
-     * @param int    $couponId 优惠券ID
-     * @param int    $goodsId  商品ID
-     * @param int    $orderId  订单ID
-     * @param string $desc     备注
-     *
-     * @return int
-     */
-    public static function addCouponLog($couponId, $goodsId, $orderId, $desc = '')
-    {
-        $log = new CouponLog();
-        $log->coupon_id = $couponId;
-        $log->goods_id = $goodsId;
-        $log->order_id = $orderId;
-        $log->desc = $desc;
-
-        return $log->save();
-    }
-
-    /**
-     * 记录流量变动日志
-     *
-     * @param int    $userId 用户ID
-     * @param string $oid    订单ID
-     * @param int    $before 记录前的值
-     * @param int    $after  记录后的值
-     * @param string $desc   描述
-     *
-     * @return int
-     */
-    public static function addUserTrafficModifyLog($userId, $oid, $before, $after, $desc = '')
-    {
-        $log = new UserTrafficModifyLog();
-        $log->user_id = $userId;
-        $log->order_id = $oid;
-        $log->before = $before;
-        $log->after = $after;
-        $log->desc = $desc;
-
-        return $log->save();
-    }
+	// 不生成的端口
+	private static $denyPorts = [
+		1068, 1109, 1434, 3127, 3128,
+		3129, 3130, 3332, 4444, 5554,
+		6669, 8080, 8081, 8082, 8181,
+		8282, 9996, 17185, 24554, 35601,
+		60177, 60179
+	];
+
+	// 获取系统配置
+	public static function systemConfig()
+	{
+		$config = Config::query()->get();
+		$data = [];
+		foreach($config as $vo){
+			$data[$vo->name] = $vo->value;
+		}
+
+		return $data;
+	}
+
+	// 获取默认加密方式
+	public static function getDefaultMethod()
+	{
+		$config = SsConfig::default()->type(1)->first();
+
+		return $config? $config->name : 'aes-256-cfb';
+	}
+
+	// 获取默认协议
+	public static function getDefaultProtocol()
+	{
+		$config = SsConfig::default()->type(2)->first();
+
+		return $config? $config->name : 'origin';
+	}
+
+	// 获取默认混淆
+	public static function getDefaultObfs()
+	{
+		$config = SsConfig::default()->type(3)->first();
+
+		return $config? $config->name : 'plain';
+	}
+
+	// 获取一个随机端口
+	public static function getRandPort()
+	{
+		$config = self::systemConfig();
+		$port = mt_rand($config['min_port'], $config['max_port']);
+
+		$exists_port = User::query()->pluck('port')->toArray();
+		if(in_array($port, $exists_port) || in_array($port, self::$denyPorts)){
+			$port = self::getRandPort();
+		}
+
+		return $port;
+	}
+
+	// 获取一个端口
+	public static function getOnlyPort()
+	{
+		$config = self::systemConfig();
+		$port = $config['min_port'];
+
+		$exists_port = User::query()->where('port', '>=', $config['min_port'])->pluck('port')->toArray();
+		while(in_array($port, $exists_port) || in_array($port, self::$denyPorts)){
+			$port = $port+1;
+		}
+
+		return $port;
+	}
+
+	// 加密方式
+	public static function methodList()
+	{
+		return SsConfig::type(1)->get();
+	}
+
+	// 协议
+	public static function protocolList()
+	{
+		return SsConfig::type(2)->get();
+	}
+
+	// 混淆
+	public static function obfsList()
+	{
+		return SsConfig::type(3)->get();
+	}
+
+	// 等级
+	public static function levelList()
+	{
+		return Level::query()->get()->sortBy('level');
+	}
+
+	// 生成用户的订阅码
+	public static function makeSubscribeCode()
+	{
+		$code = makeRandStr(5);
+		if(UserSubscribe::query()->where('code', $code)->exists()){
+			$code = self::makeSubscribeCode();
+		}
+
+		return $code;
+	}
+
+	/**
+	 * 添加邮件投递日志
+	 *
+	 * @param string $address 收信地址
+	 * @param string $title   标题
+	 * @param string $content 内容
+	 * @param int    $status  投递状态
+	 * @param string $error   投递失败时记录的异常信息
+	 *
+	 * @return int
+	 */
+	public static function addEmailLog($address, $title, $content, $status = 1, $error = '')
+	{
+		$log = new EmailLog();
+		$log->type = 1;
+		$log->address = $address;
+		$log->title = $title;
+		$log->content = $content;
+		$log->status = $status;
+		$log->error = $error;
+		$log->save();
+
+		return $log->id;
+	}
+
+	/**
+	 * 添加优惠券操作日志
+	 *
+	 * @param int    $couponId 优惠券ID
+	 * @param int    $goodsId  商品ID
+	 * @param int    $orderId  订单ID
+	 * @param string $desc     备注
+	 *
+	 * @return int
+	 */
+	public static function addCouponLog($couponId, $goodsId, $orderId, $desc = '')
+	{
+		$log = new CouponLog();
+		$log->coupon_id = $couponId;
+		$log->goods_id = $goodsId;
+		$log->order_id = $orderId;
+		$log->desc = $desc;
+
+		return $log->save();
+	}
+
+	/**
+	 * 记录流量变动日志
+	 *
+	 * @param int    $userId 用户ID
+	 * @param string $oid    订单ID
+	 * @param int    $before 记录前的值
+	 * @param int    $after  记录后的值
+	 * @param string $desc   描述
+	 *
+	 * @return int
+	 */
+	public static function addUserTrafficModifyLog($userId, $oid, $before, $after, $desc = '')
+	{
+		$log = new UserTrafficModifyLog();
+		$log->user_id = $userId;
+		$log->order_id = $oid;
+		$log->before = $before;
+		$log->after = $after;
+		$log->desc = $desc;
+
+		return $log->save();
+	}
 }

+ 14 - 14
app/Components/IPIP.php

@@ -6,20 +6,20 @@ use ipip\db\City;
 
 class IPIP
 {
-    /**
-     * 查询IP地址的详细信息
-     *
-     * @param string $ip IPv4
-     *
-     * @return array|null
-     */
-    public static function ip($ip)
-    {
-        $filePath = public_path('ipip.ipdb');
+	/**
+	 * 查询IP地址的详细信息
+	 *
+	 * @param string $ip IPv4
+	 *
+	 * @return array|null
+	 */
+	public static function ip($ip)
+	{
+		$filePath = public_path('ipip.ipdb');
 
-        $loc = new City($filePath);
-        $result = $loc->findMap($ip, 'CN');
+		$loc = new City($filePath);
+		$result = $loc->findMap($ip, 'CN');
 
-        return $result;
-    }
+		return $result;
+	}
 }

+ 97 - 96
app/Components/Namesilo.php

@@ -2,104 +2,105 @@
 
 namespace App\Components;
 
-use LSS\XML2Array;
+use Exception;
 use Log;
+use LSS\XML2Array;
 
 class Namesilo
 {
-    protected static $host;
-    protected static $systemConfig;
-
-    function __construct()
-    {
-        self::$host = 'https://www.namesilo.com/api/';
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    // 列出账号下所有域名
-    public function listDomains()
-    {
-        return $this->send('listDomains');
-    }
-
-    // 列出指定域名的所有DNS记录
-    public function dnsListRecords($domain)
-    {
-        $query = [
-            'domain' => $domain
-        ];
-
-        return $this->send('dnsListRecords', $query);
-    }
-
-    // 为指定域名添加DNS记录
-    public function dnsAddRecord($domain, $host, $value, $type = 'A', $ttl = 7207)
-    {
-        $query = [
-            'domain'  => $domain,
-            'rrtype'  => $type,
-            'rrhost'  => $host,
-            'rrvalue' => $value,
-            'rrttl'   => $ttl
-        ];
-
-        return $this->send('dnsAddRecord', $query);
-    }
-
-    // 更新DNS记录
-    public function dnsUpdateRecord($domain, $id, $host, $value, $ttl = 7207)
-    {
-        $query = [
-            'domain'  => $domain,
-            'rrid'    => $id,
-            'rrhost'  => $host,
-            'rrvalue' => $value,
-            'rrttl'   => $ttl
-        ];
-
-        return $this->send('dnsUpdateRecord', $query);
-    }
-
-    // 删除DNS记录
-    public function dnsDeleteRecord($domain, $id)
-    {
-        $data = [
-            'domain' => $domain,
-            'rrid'   => $id
-        ];
-
-        return $this->send('dnsDeleteRecord', $data);
-    }
-
-    // 发送请求
-    private function send($operation, $data = [])
-    {
-        $params = [
-            'version' => 1,
-            'type'    => 'xml',
-            'key'     => self::$systemConfig['namesilo_key']
-        ];
-        $query = array_merge($params, $data);
-
-        $content = '请求操作:[' . $operation . '] --- 请求数据:[' . http_build_query($query) . ']';
-
-        try {
-            $result = Curl::send(self::$host . $operation . '?' . http_build_query($query));
-            $result = XML2Array::createArray($result);
-
-            // 出错
-            if (empty($result['namesilo']) || $result['namesilo']['reply']['code'] != 300 || $result['namesilo']['reply']['detail'] != 'success') {
-                Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], '[Namesilo API] - [' . $operation . ']', $content, 0, $result['namesilo']['reply']['detail']);
-            } else {
-                Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], '[Namesilo API] - [' . $operation . ']', $content, 1, $result['namesilo']['reply']['detail']);
-            }
-
-            return $result['namesilo']['reply'];
-        } catch (\Exception $e) {
-            Log::error('CURL请求失败:' . $e->getMessage() . ' --- ' . $e->getLine());
-            Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], '[Namesilo API] - [' . $operation . ']', $content, 0, $e->getMessage());
-
-            return false;
-        }
-    }
+	protected static $host;
+	protected static $systemConfig;
+
+	function __construct()
+	{
+		self::$host = 'https://www.namesilo.com/api/';
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	// 列出账号下所有域名
+	public function listDomains()
+	{
+		return $this->send('listDomains');
+	}
+
+	// 列出指定域名的所有DNS记录
+	public function dnsListRecords($domain)
+	{
+		$query = [
+			'domain' => $domain
+		];
+
+		return $this->send('dnsListRecords', $query);
+	}
+
+	// 为指定域名添加DNS记录
+	public function dnsAddRecord($domain, $host, $value, $type = 'A', $ttl = 7207)
+	{
+		$query = [
+			'domain'  => $domain,
+			'rrtype'  => $type,
+			'rrhost'  => $host,
+			'rrvalue' => $value,
+			'rrttl'   => $ttl
+		];
+
+		return $this->send('dnsAddRecord', $query);
+	}
+
+	// 更新DNS记录
+	public function dnsUpdateRecord($domain, $id, $host, $value, $ttl = 7207)
+	{
+		$query = [
+			'domain'  => $domain,
+			'rrid'    => $id,
+			'rrhost'  => $host,
+			'rrvalue' => $value,
+			'rrttl'   => $ttl
+		];
+
+		return $this->send('dnsUpdateRecord', $query);
+	}
+
+	// 删除DNS记录
+	public function dnsDeleteRecord($domain, $id)
+	{
+		$data = [
+			'domain' => $domain,
+			'rrid'   => $id
+		];
+
+		return $this->send('dnsDeleteRecord', $data);
+	}
+
+	// 发送请求
+	private function send($operation, $data = [])
+	{
+		$params = [
+			'version' => 1,
+			'type'    => 'xml',
+			'key'     => self::$systemConfig['namesilo_key']
+		];
+		$query = array_merge($params, $data);
+
+		$content = '请求操作:['.$operation.'] --- 请求数据:['.http_build_query($query).']';
+
+		try{
+			$result = Curl::send(self::$host.$operation.'?'.http_build_query($query));
+			$result = XML2Array::createArray($result);
+
+			// 出错
+			if(empty($result['namesilo']) || $result['namesilo']['reply']['code'] != 300 || $result['namesilo']['reply']['detail'] != 'success'){
+				Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], '[Namesilo API] - ['.$operation.']', $content, 0, $result['namesilo']['reply']['detail']);
+			}else{
+				Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], '[Namesilo API] - ['.$operation.']', $content, 1, $result['namesilo']['reply']['detail']);
+			}
+
+			return $result['namesilo']['reply'];
+		} catch(Exception $e){
+			Log::error('CURL请求失败:'.$e->getMessage().' --- '.$e->getLine());
+			Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], '[Namesilo API] - ['.$operation.']', $content, 0, $e->getMessage());
+
+			return FALSE;
+		}
+	}
 }

+ 12 - 12
app/Components/QQWry.php

@@ -6,17 +6,17 @@ use itbdw\Ip\IpLocation;
 
 class QQWry
 {
-    /**
-     * 查询IP地址的详细信息
-     *
-     * @param string $ip IPv4
-     *
-     * @return array
-     */
-    public static function ip($ip)
-    {
-        $filePath = public_path('qqwry.dat');
+	/**
+	 * 查询IP地址的详细信息
+	 *
+	 * @param string $ip IPv4
+	 *
+	 * @return array
+	 */
+	public static function ip($ip)
+	{
+		$filePath = public_path('qqwry.dat');
 
-        return IpLocation::getLocation($ip, $filePath);
-    }
+		return IpLocation::getLocation($ip, $filePath);
+	}
 }

+ 50 - 49
app/Components/ServerChan.php

@@ -3,59 +3,60 @@
 namespace App\Components;
 
 use App\Http\Models\EmailLog;
+use Exception;
 use Log;
 
 class ServerChan
 {
-    /**
-     * 推送消息
-     *
-     * @param string $title   消息标题
-     * @param string $content 消息内容
-     *
-     * @return mixed
-     */
-    public static function send($title, $content)
-    {
-        if (Helpers::systemConfig()['is_server_chan'] && Helpers::systemConfig()['server_chan_key']) {
-            try {
-                // TODO:一天仅可发送不超过500条
-                $url = 'https://sc.ftqq.com/' . Helpers::systemConfig()['server_chan_key'] . '.send?text=' . $title . '&desp=' . urlencode($content);
-                $response = Curl::send($url);
-                $result = json_decode($response);
-                if (!$result->errno) {
-                    self::addLog($title, $content);
-                } else {
-                    self::addLog($title, $content, 0, $result->errmsg);
-                }
-            } catch (\Exception $e) {
-                Log::error('ServerChan消息推送异常:' . $e);
-            }
-        } else {
-            Log::error('消息推送失败:未启用或未正确配置ServerChan');
-        }
-    }
+	/**
+	 * 推送消息
+	 *
+	 * @param string $title   消息标题
+	 * @param string $content 消息内容
+	 *
+	 * @return mixed
+	 */
+	public static function send($title, $content)
+	{
+		if(Helpers::systemConfig()['is_server_chan'] && Helpers::systemConfig()['server_chan_key']){
+			try{
+				// TODO:一天仅可发送不超过500条
+				$url = 'https://sc.ftqq.com/'.Helpers::systemConfig()['server_chan_key'].'.send?text='.$title.'&desp='.urlencode($content);
+				$response = Curl::send($url);
+				$result = json_decode($response);
+				if(!$result->errno){
+					self::addLog($title, $content);
+				}else{
+					self::addLog($title, $content, 0, $result->errmsg);
+				}
+			} catch(Exception $e){
+				Log::error('ServerChan消息推送异常:'.$e);
+			}
+		}else{
+			Log::error('消息推送失败:未启用或未正确配置ServerChan');
+		}
+	}
 
-    /**
-     * 添加serverChan推送日志
-     *
-     * @param string $title   标题
-     * @param string $content 内容
-     * @param int    $status  投递状态
-     * @param string $error   投递失败时记录的异常信息
-     *
-     * @return int
-     */
-    private static function addLog($title, $content, $status = 1, $error = '')
-    {
-        $log = new EmailLog();
-        $log->type = 2;
-        $log->address = 'admin';
-        $log->title = $title;
-        $log->content = $content;
-        $log->status = $status;
-        $log->error = $error;
+	/**
+	 * 添加serverChan推送日志
+	 *
+	 * @param string $title   标题
+	 * @param string $content 内容
+	 * @param int    $status  投递状态
+	 * @param string $error   投递失败时记录的异常信息
+	 *
+	 * @return int
+	 */
+	private static function addLog($title, $content, $status = 1, $error = '')
+	{
+		$log = new EmailLog();
+		$log->type = 2;
+		$log->address = 'admin';
+		$log->title = $title;
+		$log->content = $content;
+		$log->status = $status;
+		$log->error = $error;
 
-        return $log->save();
-    }
+		return $log->save();
+	}
 }

+ 65 - 63
app/Components/Yzy.php

@@ -4,70 +4,72 @@ namespace App\Components;
 
 use Cache;
 use Log;
+use Youzan\Open\Client;
+use Youzan\Open\Token;
 
 class Yzy
 {
-    protected static $systemConfig;
-    protected static $accessToken;
-
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-        self::$accessToken = $this->getAccessToken();
-    }
-
-    // 获取accessToken
-    public function getAccessToken()
-    {
-        if (Cache::has('YZY_TOKEN')) {
-            $token = Cache::get('YZY_TOKEN');
-            if (!isset($token['error'])) {
-                return Cache::get('YZY_TOKEN')['access_token'];
-            }
-
-            Cache::forget('YZY_TOKEN');
-        }
-
-        $token = (new \Youzan\Open\Token(self::$systemConfig['youzan_client_id'], self::$systemConfig['youzan_client_secret']))->getToken('self', ['kdt_id' => self::$systemConfig['kdt_id']]);
-        if (isset($token['error'])) {
-            Log::info('获取有赞云支付access_token失败:' . $token['error_description']);
-
-            return '';
-        } else {
-            Cache::put('YZY_TOKEN', $token, 180);
-
-            return $token['access_token'];
-        }
-    }
-
-    // 生成收款二维码
-    public function createQrCode($goodsName, $price, $orderSn)
-    {
-        $client = new \Youzan\Open\Client(self::$accessToken);
-
-        $params = [
-            'qr_name'   => $goodsName, // 商品名
-            'qr_price'  => $price, // 单位分
-            'qr_source' => $orderSn, // 本地订单号
-            'qr_type'   => 'QR_TYPE_DYNAMIC'
-        ];
-
-        return $client->get('youzan.pay.qrcode.create', '3.0.0', $params);
-    }
-
-    // 通过tid获取交易信息
-    public function getTradeByTid($tid)
-    {
-        $client = new \Youzan\Open\Client(self::$accessToken);
-
-        return $client->post('youzan.trade.get', '4.0.0', ['tid' => $tid]);
-    }
-
-    // 通过二维码ID获取已支付的交易信息
-    public function getTradeByQrId($qr_id)
-    {
-        $client = new \Youzan\Open\Client(self::$accessToken);
-
-        return $client->post('youzan.trades.qr.get', '3.0.0', ['qr_id' => $qr_id, 'status' => 'TRADE_RECEIVED']);
-    }
+	protected static $systemConfig;
+	protected static $accessToken;
+
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+		self::$accessToken = $this->getAccessToken();
+	}
+
+	// 获取accessToken
+	public function getAccessToken()
+	{
+		if(Cache::has('YZY_TOKEN')){
+			$token = Cache::get('YZY_TOKEN');
+			if(!isset($token['error'])){
+				return Cache::get('YZY_TOKEN')['access_token'];
+			}
+
+			Cache::forget('YZY_TOKEN');
+		}
+
+		$token = (new Token(self::$systemConfig['youzan_client_id'], self::$systemConfig['youzan_client_secret']))->getToken('self', ['kdt_id' => self::$systemConfig['kdt_id']]);
+		if(isset($token['error'])){
+			Log::info('获取有赞云支付access_token失败:'.$token['error_description']);
+
+			return '';
+		}else{
+			Cache::put('YZY_TOKEN', $token, 180);
+
+			return $token['access_token'];
+		}
+	}
+
+	// 生成收款二维码
+	public function createQrCode($goodsName, $price, $orderSn)
+	{
+		$client = new Client(self::$accessToken);
+
+		$params = [
+			'qr_name'   => $goodsName, // 商品名
+			'qr_price'  => $price, // 单位分
+			'qr_source' => $orderSn, // 本地订单号
+			'qr_type'   => 'QR_TYPE_DYNAMIC'
+		];
+
+		return $client->get('youzan.pay.qrcode.create', '3.0.0', $params);
+	}
+
+	// 通过tid获取交易信息
+	public function getTradeByTid($tid)
+	{
+		$client = new Client(self::$accessToken);
+
+		return $client->post('youzan.trade.get', '4.0.0', ['tid' => $tid]);
+	}
+
+	// 通过二维码ID获取已支付的交易信息
+	public function getTradeByQrId($qr_id)
+	{
+		$client = new Client(self::$accessToken);
+
+		return $client->post('youzan.trades.qr.get', '3.0.0', ['qr_id' => $qr_id, 'status' => 'TRADE_RECEIVED']);
+	}
 }

+ 188 - 187
app/Console/Commands/AutoCheckNodeTCP.php

@@ -3,207 +3,208 @@
 namespace App\Console\Commands;
 
 use App\Components\Helpers;
-use Illuminate\Console\Command;
 use App\Components\ServerChan;
 use App\Http\Models\SsNode;
-use App\Http\Models\SsNodeInfo;
 use App\Mail\nodeCrashWarning;
 use Cache;
-use Mail;
+use Exception;
+use GuzzleHttp\Exception\GuzzleException;
+use Illuminate\Console\Command;
 use Log;
+use Mail;
 
 class AutoCheckNodeTCP extends Command
 {
-    protected $signature = 'autoCheckNodeTCP';
-    protected $description = '自动检测节点是否被TCP阻断';
-    protected static $systemConfig;
-
-    public function __construct()
-    {
-        parent::__construct();
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
-
-        if (self::$systemConfig['is_tcp_check']) {
-            if (!Cache::has('tcp_check_time')) {
-                $this->checkNodes();
-            } elseif (Cache::get('tcp_check_time') <= time()) {
-                $this->checkNodes();
-            } else {
-                Log::info('下次节点TCP阻断检测时间:' . date('Y-m-d H:i:s', Cache::get('tcp_check_time')));
-            }
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
-
-    // 监测节点状态
-    private function checkNodes()
-    {
-        $title = "节点异常警告";
-
-        $nodeList = SsNode::query()->where('is_transit', 0)->where('is_nat', 0)->where('status', 1)->where('is_tcp_check', 1)->get();
-        foreach ($nodeList as $node) {
-            $tcpCheck = $this->tcpCheck($node->ip);
-            if (false !== $tcpCheck) {
-                switch ($tcpCheck) {
-                    case 1:
-                        $text = '服务器宕机';
-                        break;
-                    case 2:
-                        $text = '海外不通';
-                        break;
-                    case 3:
-                        $text = 'TCP阻断';
-                        break;
-                    case 0:
-                    default:
-                        $text = '正常';
-                }
-
-                // 异常才发通知消息
-                if ($tcpCheck) {
-                    if (self::$systemConfig['tcp_check_warning_times']) {
-                        // 已通知次数
-                        $cacheKey = 'tcp_check_warning_times_' . $node->id;
-                        if (Cache::has($cacheKey)) {
-                            $times = Cache::get($cacheKey);
-                        } else {
-                            Cache::put($cacheKey, 1, 725); // 最多设置提醒12次,12*60=720分钟缓存时效,多5分钟防止异常
-                            $times = 1;
-                        }
-
-                        if ($times < self::$systemConfig['tcp_check_warning_times']) {
-                            Cache::increment($cacheKey);
-
-                            $this->notifyMaster($title, "节点**{$node->name}【{$node->ip}】**:**" . $text . "**", $node->name, $node->server);
-                        } elseif ($times >= self::$systemConfig['tcp_check_warning_times']) {
-                            Cache::forget($cacheKey);
-                            SsNode::query()->where('id', $node->id)->update(['status' => 0]);
-
-                            $this->notifyMaster($title, "节点**{$node->name}【{$node->ip}】**:**" . $text . "**,节点自动进入维护状态", $node->name, $node->server);
-                        }
-                    } else {
-                        $this->notifyMaster($title, "节点**{$node->name}【{$node->ip}】**:**" . $text . "**", $node->name, $node->server);
-                    }
-                }
-
-                Log::info("【TCP阻断检测】" . $node->name . ' - ' . $node->ip . ' - ' . $text);
-            }
-        }
-
-        // 随机生成下次检测时间
-        $nextCheckTime = time() + mt_rand(1800, 3600);
-        Cache::put('tcp_check_time', $nextCheckTime, 60);
-    }
-
-    /**
-     * 用ipcheck.need.sh进行TCP阻断检测
-     *
-     * @param string $ip 被检测的IP
-     *
-     * @return bool|int
-     */
-    private function tcpCheck($ip)
-    {
-        try {
-            $url = 'https://ipcheck.need.sh/api_v2.php?ip=' . $ip;
-            $ret = $this->curlRequest($url);
-            $ret = json_decode($ret);
-            if (!$ret || $ret->result != 'success') {
-                Log::warning("【TCP阻断检测】检测" . $ip . "时,接口返回异常");
-
-                return false;
-            }
-        } catch (\Exception $e) {
-            Log::warning("【TCP阻断检测】检测" . $ip . "时,接口请求超时");
-
-            return false;
-        }
-
-        if (!$ret->data->inside_gfw->tcp->alive && !$ret->data->outside_gfw->tcp->alive) {
-            return 1; // 服务器宕机或者检测接口挂了
-        } elseif ($ret->data->inside_gfw->tcp->alive && !$ret->data->outside_gfw->tcp->alive) {
-            return 2; // 国外访问异常
-        } elseif (!$ret->data->inside_gfw->tcp->alive && $ret->data->outside_gfw->tcp->alive) {
-            return 3; // 被墙
-        } else {
-            return 0; // 正常
-        }
-    }
-
-    /**
-     * 通知管理员
-     *
-     * @param string $title      消息标题
-     * @param string $content    消息内容
-     * @param string $nodeName   节点名称
-     * @param string $nodeServer 节点域名
-     *
-     * @throws \GuzzleHttp\Exception\GuzzleException
-     */
-    private function notifyMaster($title, $content, $nodeName, $nodeServer)
-    {
-        $this->notifyMasterByEmail($title, $content, $nodeName, $nodeServer);
-        ServerChan::send($title, $content);
-    }
-
-    /**
-     * 发邮件通知管理员
-     *
-     * @param string $title      消息标题
-     * @param string $content    消息内容
-     * @param string $nodeName   节点名称
-     * @param string $nodeServer 节点域名
-     */
-    private function notifyMasterByEmail($title, $content, $nodeName, $nodeServer)
-    {
-        if (self::$systemConfig['crash_warning_email']) {
-            $logId = Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], $title, $content);
-            Mail::to(self::$systemConfig['crash_warning_email'])->send(new nodeCrashWarning($logId, $nodeName, $nodeServer));
-        }
-    }
-
-    /**
-     * 发起一个CURL请求
-     *
-     * @param string $url  请求地址
-     * @param array  $data POST数据,留空则为GET
-     *
-     * @return mixed
-     */
-    private function curlRequest($url, $data = [])
-    {
-        $data = json_encode($data, JSON_UNESCAPED_UNICODE);
-
-        $ch = curl_init();
-        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
-        curl_setopt($ch, CURLOPT_TIMEOUT, 10);
-        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
-        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
-        curl_setopt($ch, CURLOPT_URL, $url);
+	protected $signature = 'autoCheckNodeTCP';
+	protected $description = '自动检测节点是否被TCP阻断';
+	protected static $systemConfig;
+
+	public function __construct()
+	{
+		parent::__construct();
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
+
+		if(self::$systemConfig['is_tcp_check']){
+			if(!Cache::has('tcp_check_time')){
+				$this->checkNodes();
+			}elseif(Cache::get('tcp_check_time') <= time()){
+				$this->checkNodes();
+			}else{
+				Log::info('下次节点TCP阻断检测时间:'.date('Y-m-d H:i:s', Cache::get('tcp_check_time')));
+			}
+		}
+
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
+
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
+
+	// 监测节点状态
+	private function checkNodes()
+	{
+		$title = "节点异常警告";
+
+		$nodeList = SsNode::query()->where('is_transit', 0)->where('is_nat', 0)->where('status', 1)->where('is_tcp_check', 1)->get();
+		foreach($nodeList as $node){
+			$tcpCheck = $this->tcpCheck($node->ip);
+			if(FALSE !== $tcpCheck){
+				switch($tcpCheck){
+					case 1:
+						$text = '服务器宕机';
+						break;
+					case 2:
+						$text = '海外不通';
+						break;
+					case 3:
+						$text = 'TCP阻断';
+						break;
+					case 0:
+					default:
+						$text = '正常';
+				}
+
+				// 异常才发通知消息
+				if($tcpCheck){
+					if(self::$systemConfig['tcp_check_warning_times']){
+						// 已通知次数
+						$cacheKey = 'tcp_check_warning_times_'.$node->id;
+						if(Cache::has($cacheKey)){
+							$times = Cache::get($cacheKey);
+						}else{
+							Cache::put($cacheKey, 1, 725); // 最多设置提醒12次,12*60=720分钟缓存时效,多5分钟防止异常
+							$times = 1;
+						}
+
+						if($times < self::$systemConfig['tcp_check_warning_times']){
+							Cache::increment($cacheKey);
+
+							$this->notifyMaster($title, "节点**{$node->name}【{$node->ip}】**:**".$text."**", $node->name, $node->server);
+						}elseif($times >= self::$systemConfig['tcp_check_warning_times']){
+							Cache::forget($cacheKey);
+							SsNode::query()->where('id', $node->id)->update(['status' => 0]);
+
+							$this->notifyMaster($title, "节点**{$node->name}【{$node->ip}】**:**".$text."**,节点自动进入维护状态", $node->name, $node->server);
+						}
+					}else{
+						$this->notifyMaster($title, "节点**{$node->name}【{$node->ip}】**:**".$text."**", $node->name, $node->server);
+					}
+				}
+
+				Log::info("【TCP阻断检测】".$node->name.' - '.$node->ip.' - '.$text);
+			}
+		}
+
+		// 随机生成下次检测时间
+		$nextCheckTime = time()+mt_rand(1800, 3600);
+		Cache::put('tcp_check_time', $nextCheckTime, 60);
+	}
+
+	/**
+	 * 用ipcheck.need.sh进行TCP阻断检测
+	 *
+	 * @param string $ip 被检测的IP
+	 *
+	 * @return bool|int
+	 */
+	private function tcpCheck($ip)
+	{
+		try{
+			$url = 'https://ipcheck.need.sh/api_v2.php?ip='.$ip;
+			$ret = $this->curlRequest($url);
+			$ret = json_decode($ret);
+			if(!$ret || $ret->result != 'success'){
+				Log::warning("【TCP阻断检测】检测".$ip."时,接口返回异常");
+
+				return FALSE;
+			}
+		} catch(Exception $e){
+			Log::warning("【TCP阻断检测】检测".$ip."时,接口请求超时");
+
+			return FALSE;
+		}
+
+		if(!$ret->data->inside_gfw->tcp->alive && !$ret->data->outside_gfw->tcp->alive){
+			return 1; // 服务器宕机或者检测接口挂了
+		}elseif($ret->data->inside_gfw->tcp->alive && !$ret->data->outside_gfw->tcp->alive){
+			return 2; // 国外访问异常
+		}elseif(!$ret->data->inside_gfw->tcp->alive && $ret->data->outside_gfw->tcp->alive){
+			return 3; // 被墙
+		}else{
+			return 0; // 正常
+		}
+	}
+
+	/**
+	 * 通知管理员
+	 *
+	 * @param string $title      消息标题
+	 * @param string $content    消息内容
+	 * @param string $nodeName   节点名称
+	 * @param string $nodeServer 节点域名
+	 *
+	 * @throws GuzzleException
+	 */
+	private function notifyMaster($title, $content, $nodeName, $nodeServer)
+	{
+		$this->notifyMasterByEmail($title, $content, $nodeName, $nodeServer);
+		ServerChan::send($title, $content);
+	}
+
+	/**
+	 * 发邮件通知管理员
+	 *
+	 * @param string $title      消息标题
+	 * @param string $content    消息内容
+	 * @param string $nodeName   节点名称
+	 * @param string $nodeServer 节点域名
+	 */
+	private function notifyMasterByEmail($title, $content, $nodeName, $nodeServer)
+	{
+		if(self::$systemConfig['crash_warning_email']){
+			$logId = Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], $title, $content);
+			Mail::to(self::$systemConfig['crash_warning_email'])->send(new nodeCrashWarning($logId, $nodeName, $nodeServer));
+		}
+	}
+
+	/**
+	 * 发起一个CURL请求
+	 *
+	 * @param string $url  请求地址
+	 * @param array  $data POST数据,留空则为GET
+	 *
+	 * @return mixed
+	 */
+	private function curlRequest($url, $data = [])
+	{
+		$data = json_encode($data, JSON_UNESCAPED_UNICODE);
+
+		$ch = curl_init();
+		curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
+		curl_setopt($ch, CURLOPT_TIMEOUT, 10);
+		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
+		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
+		curl_setopt($ch, CURLOPT_URL, $url);
 //        curl_setopt($ch, CURLOPT_HTTPHEADER, [
 //            'Accept: application/json', // 请求报头
 //            'Content-Type: application/json', // 实体报头
 //            'Content-Length: ' . strlen($data)
 //        ]);
 
-        // 如果data有数据,则用POST请求
-        if ($data) {
-            curl_setopt($ch, CURLOPT_POST, 1);
-            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
-        }
+		// 如果data有数据,则用POST请求
+		if($data){
+			curl_setopt($ch, CURLOPT_POST, 1);
+			curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
+		}
 
-        $result = curl_exec($ch);
-        curl_close($ch);
+		$result = curl_exec($ch);
+		curl_close($ch);
 
-        return $result;
-    }
+		return $result;
+	}
 }

+ 48 - 48
app/Console/Commands/AutoClearLog.php

@@ -3,82 +3,82 @@
 namespace App\Console\Commands;
 
 use App\Components\Helpers;
-use App\Http\Models\SsNodeIp;
 use App\Http\Models\SsNodeInfo;
+use App\Http\Models\SsNodeIp;
 use App\Http\Models\SsNodeOnlineLog;
-use App\Http\Models\SsNodeTrafficHourly;
 use App\Http\Models\SsNodeTrafficDaily;
+use App\Http\Models\SsNodeTrafficHourly;
 use App\Http\Models\UserBanLog;
 use App\Http\Models\UserLoginLog;
 use App\Http\Models\UserSubscribeLog;
 use App\Http\Models\UserTrafficDaily;
-use App\Http\Models\UserTrafficLog;
 use App\Http\Models\UserTrafficHourly;
+use App\Http\Models\UserTrafficLog;
 use Illuminate\Console\Command;
 use Log;
 
 class AutoClearLog extends Command
 {
-    protected $signature = 'autoClearLog';
-    protected $description = '自动清除日志';
-    protected static $systemConfig;
+	protected $signature = 'autoClearLog';
+	protected $description = '自动清除日志';
+	protected static $systemConfig;
 
-    public function __construct()
-    {
-        parent::__construct();
-        self::$systemConfig = Helpers::systemConfig();
-    }
+	public function __construct()
+	{
+		parent::__construct();
+		self::$systemConfig = Helpers::systemConfig();
+	}
 
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
 
-        // 清除日志
-        if (self::$systemConfig['is_clear_log']) {
-            $this->clearLog();
-        }
+		// 清除日志
+		if(self::$systemConfig['is_clear_log']){
+			$this->clearLog();
+		}
 
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
 
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
 
-    // 清除日志
-    private function clearLog()
-    {
-        // 自动清除30分钟以前的节点负载信息日志
-        SsNodeInfo::query()->where('log_time', '<=', strtotime("-30 minutes"))->delete();
+	// 清除日志
+	private function clearLog()
+	{
+		// 自动清除30分钟以前的节点负载信息日志
+		SsNodeInfo::query()->where('log_time', '<=', strtotime("-30 minutes"))->delete();
 
-        // 自动清除1小时以前的节点在线用户数日志
-        SsNodeOnlineLog::query()->where('log_time', '<=', strtotime("-1 hour"))->delete();
+		// 自动清除1小时以前的节点在线用户数日志
+		SsNodeOnlineLog::query()->where('log_time', '<=', strtotime("-1 hour"))->delete();
 
-        // 自动清除3天以前的用户流量日志
-        UserTrafficLog::query()->where('log_time', '<=', strtotime("-3 days"))->delete();
+		// 自动清除3天以前的用户流量日志
+		UserTrafficLog::query()->where('log_time', '<=', strtotime("-3 days"))->delete();
 
-        // 自动清除3天以前的用户每小时流量数据日志
-        UserTrafficHourly::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 days')))->delete();
+		// 自动清除3天以前的用户每小时流量数据日志
+		UserTrafficHourly::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 days')))->delete();
 
-        // 自动清除1个月以前的用户每天流量数据日志
-        UserTrafficDaily::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-1 month')))->delete();
+		// 自动清除1个月以前的用户每天流量数据日志
+		UserTrafficDaily::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-1 month')))->delete();
 
-        // 自动清除2个月以前的节点每小时流量数据日志
-        SsNodeTrafficHourly::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-2 month')))->delete();
+		// 自动清除2个月以前的节点每小时流量数据日志
+		SsNodeTrafficHourly::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-2 month')))->delete();
 
-        // 自动清除3个月以前的节点每天流量数据日志
-        SsNodeTrafficDaily::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 month')))->delete();
+		// 自动清除3个月以前的节点每天流量数据日志
+		SsNodeTrafficDaily::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime('-3 month')))->delete();
 
-        // 自动清除30天以前用户封禁日志
-        UserBanLog::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-1 month")))->delete();
+		// 自动清除30天以前用户封禁日志
+		UserBanLog::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-1 month")))->delete();
 
-        // 自动清除1天前用户连接IP
-        SsNodeIp::query()->where('created_at', '<=', strtotime("-1 day"))->delete();
+		// 自动清除1天前用户连接IP
+		SsNodeIp::query()->where('created_at', '<=', strtotime("-1 day"))->delete();
 
-        // 自动清除3个月以前用户登陆日志
-        UserLoginLog::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-3 month")))->delete();
+		// 自动清除3个月以前用户登陆日志
+		UserLoginLog::query()->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-3 month")))->delete();
 
-        // 自动清除1个月前的用户订阅记录
-        UserSubscribeLog::query()->where('request_time', '<=', date('Y-m-d H:i:s', strtotime("-1 month")))->delete();
-    }
+		// 自动清除1个月前的用户订阅记录
+		UserSubscribeLog::query()->where('request_time', '<=', date('Y-m-d H:i:s', strtotime("-1 month")))->delete();
+	}
 
 }

+ 113 - 112
app/Console/Commands/AutoDecGoodsTraffic.php

@@ -3,123 +3,124 @@
 namespace App\Console\Commands;
 
 use App\Components\Helpers;
-use Illuminate\Console\Command;
+use App\Http\Models\GoodsLabel;
 use App\Http\Models\Order;
 use App\Http\Models\User;
 use App\Http\Models\UserLabel;
-use App\Http\Models\GoodsLabel;
-use Log;
 use DB;
+use Exception;
+use Illuminate\Console\Command;
+use Log;
 
 class AutoDecGoodsTraffic extends Command
 {
-    protected $signature = 'autoDecGoodsTraffic';
-    protected $description = '自动扣减用户到期商品的流量';
-    protected static $systemConfig;
-
-    public function __construct()
-    {
-        parent::__construct();
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
-
-        // 扣减用户到期商品的流量
-        $this->decGoodsTraffic();
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
-
-    // 扣减用户到期商品的流量
-    private function decGoodsTraffic()
-    {
-        $orderList = Order::query()->with(['user', 'goods'])->where('status', 2)->where('is_expire', 0)->where('expire_at', '<', date('Y-m-d H:i:s'))->get();
-        if (!$orderList->isEmpty()) {
-            // 用户默认标签
-            $defaultLabels = [];
-            if (self::$systemConfig['initial_labels_for_user']) {
-                $defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
-            }
-
-            DB::beginTransaction();
-            try {
-                foreach ($orderList as $order) {
-                    // 先过期本订单
-                    Order::query()->where('oid', $order->oid)->update(['is_expire' => 1]);
-
-                    // 再检查该订单对应用户是否还有套餐(非流量包)存在
-                    $haveOrder = Order::query()
-                        ->with(['user', 'goods'])
-                        ->where('is_expire', 0)
-                        ->where('user_id', $order->user_id)
-                        ->whereHas('goods', function ($q) {
-                            $q->where('type', 2);
-                        })
-                        ->orderBy('oid', 'desc')
-                        ->first();
-                    if (!$haveOrder) {
-                        // 如果不存在有效套餐(非流量包),则清空用户重置日
-                        User::query()->where('id', $order->user_id)->update(['traffic_reset_day' => 0]);
-                    }
-
-                    if (empty($order->user) || empty($order->goods)) {
-                        continue;
-                    }
-
-                    if ($order->user->transfer_enable - $order->goods->traffic * 1048576 <= 0) {
-                        // 写入用户流量变动记录
-                        Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $order->user->transfer_enable, 0, '[定时任务]用户所购商品到期,扣减商品对应的流量(扣完并重置)');
-
-                        User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
-                    } else {
-                        // 写入用户流量变动记录
-                        Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $order->user->transfer_enable, ($order->user->transfer_enable - $order->goods->traffic * 1048576), '[定时任务]用户所购商品到期,扣减商品对应的流量(没扣完)');
-
-                        User::query()->where('id', $order->user_id)->decrement('transfer_enable', $order->goods->traffic * 1048576);
-
-                        // 处理已用流量
-                        if ($order->user->u + $order->user->d - $order->goods->traffic * 1048576 <= 0) {
-                            User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0]);
-                        } else {
-                            // 一般来说d的值远远大于u
-                            if ($order->user->d - $order->goods->traffic * 1048576 >= 0) {
-                                User::query()->where('id', $order->user_id)->decrement('d', $order->goods->traffic * 1048576);
-                            } else { // 如果d不够减,则减u,然后d置0
-                                User::query()->where('id', $order->user_id)->decrement('u', $order->goods->traffic * 1048576 - $order->user->d);
-                                User::query()->where('id', $order->user_id)->update(['d' => 0]);
-                            }
-                        }
-                    }
-
-                    // 删除该商品对应用户的所有标签
-                    UserLabel::query()->where('user_id', $order->user->id)->delete();
-
-                    // 取出用户的其他商品带有的标签
-                    $goodsIds = Order::query()->where('user_id', $order->user->id)->where('oid', '<>', $order->oid)->where('status', 2)->where('is_expire', 0)->groupBy('goods_id')->pluck('goods_id')->toArray();
-                    $goodsLabels = GoodsLabel::query()->whereIn('goods_id', $goodsIds)->groupBy('label_id')->pluck('label_id')->toArray();
-
-                    // 生成标签
-                    $labels = array_values(array_unique(array_merge($goodsLabels, $defaultLabels))); // 标签去重
-                    foreach ($labels as $vo) {
-                        $userLabel = new UserLabel();
-                        $userLabel->user_id = $order->user->id;
-                        $userLabel->label_id = $vo;
-                        $userLabel->save();
-                    }
-                }
-
-                DB::commit();
-            } catch (\Exception $e) {
-                \Log::error($this->description . ':' . $e);
-
-                DB::rollBack();
-            }
-        }
-    }
+	protected $signature = 'autoDecGoodsTraffic';
+	protected $description = '自动扣减用户到期商品的流量';
+	protected static $systemConfig;
+
+	public function __construct()
+	{
+		parent::__construct();
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
+
+		// 扣减用户到期商品的流量
+		$this->decGoodsTraffic();
+
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
+
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
+
+	// 扣减用户到期商品的流量
+	private function decGoodsTraffic()
+	{
+		$orderList = Order::query()->with(['user', 'goods'])->where('status', 2)->where('is_expire', 0)->where('expire_at', '<', date('Y-m-d H:i:s'))->get();
+		if(!$orderList->isEmpty()){
+			// 用户默认标签
+			$defaultLabels = [];
+			if(self::$systemConfig['initial_labels_for_user']){
+				$defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
+			}
+
+			DB::beginTransaction();
+			try{
+				foreach($orderList as $order){
+					// 先过期本订单
+					Order::query()->where('oid', $order->oid)->update(['is_expire' => 1]);
+
+					// 再检查该订单对应用户是否还有套餐(非流量包)存在
+					$haveOrder = Order::query()
+						->with(['user', 'goods'])
+						->where('is_expire', 0)
+						->where('user_id', $order->user_id)
+						->whereHas('goods', function($q){
+							$q->where('type', 2);
+						})
+						->orderBy('oid', 'desc')
+						->first();
+					if(!$haveOrder){
+						// 如果不存在有效套餐(非流量包),则清空用户重置日
+						User::query()->where('id', $order->user_id)->update(['traffic_reset_day' => 0]);
+					}
+
+					if(empty($order->user) || empty($order->goods)){
+						continue;
+					}
+
+					if($order->user->transfer_enable-$order->goods->traffic*1048576 <= 0){
+						// 写入用户流量变动记录
+						Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $order->user->transfer_enable, 0, '[定时任务]用户所购商品到期,扣减商品对应的流量(扣完并重置)');
+
+						User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
+					}else{
+						// 写入用户流量变动记录
+						Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $order->user->transfer_enable, ($order->user->transfer_enable-$order->goods->traffic*1048576), '[定时任务]用户所购商品到期,扣减商品对应的流量(没扣完)');
+
+						User::query()->where('id', $order->user_id)->decrement('transfer_enable', $order->goods->traffic*1048576);
+
+						// 处理已用流量
+						if($order->user->u+$order->user->d-$order->goods->traffic*1048576 <= 0){
+							User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0]);
+						}else{
+							// 一般来说d的值远远大于u
+							if($order->user->d-$order->goods->traffic*1048576 >= 0){
+								User::query()->where('id', $order->user_id)->decrement('d', $order->goods->traffic*1048576);
+							}else{ // 如果d不够减,则减u,然后d置0
+								User::query()->where('id', $order->user_id)->decrement('u', $order->goods->traffic*1048576-$order->user->d);
+								User::query()->where('id', $order->user_id)->update(['d' => 0]);
+							}
+						}
+					}
+
+					// 删除该商品对应用户的所有标签
+					UserLabel::query()->where('user_id', $order->user->id)->delete();
+
+					// 取出用户的其他商品带有的标签
+					$goodsIds = Order::query()->where('user_id', $order->user->id)->where('oid', '<>', $order->oid)->where('status', 2)->where('is_expire', 0)->groupBy('goods_id')->pluck('goods_id')->toArray();
+					$goodsLabels = GoodsLabel::query()->whereIn('goods_id', $goodsIds)->groupBy('label_id')->pluck('label_id')->toArray();
+
+					// 生成标签
+					$labels = array_values(array_unique(array_merge($goodsLabels, $defaultLabels))); // 标签去重
+					foreach($labels as $vo){
+						$userLabel = new UserLabel();
+						$userLabel->user_id = $order->user->id;
+						$userLabel->label_id = $vo;
+						$userLabel->save();
+					}
+				}
+
+				DB::commit();
+			} catch(Exception $e){
+				Log::error($this->description.':'.$e);
+
+				DB::rollBack();
+			}
+		}
+	}
 }

+ 594 - 593
app/Console/Commands/AutoJob.php

@@ -5,614 +5,615 @@ namespace App\Console\Commands;
 use App\Components\Helpers;
 use App\Components\ServerChan;
 use App\Components\Yzy;
+use App\Http\Models\Coupon;
 use App\Http\Models\Goods;
 use App\Http\Models\GoodsLabel;
+use App\Http\Models\Invite;
+use App\Http\Models\Order;
+use App\Http\Models\Payment;
 use App\Http\Models\ReferralLog;
 use App\Http\Models\SsNode;
 use App\Http\Models\SsNodeInfo;
 use App\Http\Models\SsNodeLabel;
 use App\Http\Models\Ticket;
-use App\Http\Models\UserBalanceLog;
-use App\Http\Models\VerifyCode;
-use App\Mail\sendUserInfo;
-use Illuminate\Console\Command;
-use App\Http\Models\Coupon;
-use App\Http\Models\Invite;
-use App\Http\Models\Order;
-use App\Http\Models\Payment;
 use App\Http\Models\User;
-use App\Http\Models\UserLabel;
+use App\Http\Models\UserBalanceLog;
 use App\Http\Models\UserBanLog;
+use App\Http\Models\UserLabel;
 use App\Http\Models\UserSubscribe;
 use App\Http\Models\UserSubscribeLog;
 use App\Http\Models\UserTrafficHourly;
-use Log;
+use App\Http\Models\VerifyCode;
+use App\Mail\sendUserInfo;
 use DB;
+use Exception;
+use Illuminate\Console\Command;
+use Log;
 use Mail;
 
 class AutoJob extends Command
 {
-    protected $signature = 'autoJob';
-    protected $description = '自动化任务';
-    protected static $systemConfig;
-
-    public function __construct()
-    {
-        parent::__construct();
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    /*
-     * 警告:除非熟悉业务流程,否则不推荐更改以下执行顺序,随意变更以下顺序可能导致系统异常
-     */
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
-
-        // 注册验证码自动置无效
-        $this->expireVerifyCode();
-
-        // 优惠券到期自动置无效
-        $this->expireCoupon();
-
-        // 邀请码到期自动置无效
-        $this->expireInvite();
-
-        // 封禁访问异常的订阅链接
-        $this->blockSubscribe();
-
-        // 封禁账号
-        $this->blockUsers();
-
-        // 解封被封禁的账号
-        $this->unblockUsers();
-
-        // 端口回收与分配
-        $this->dispatchPort();
-
-        // 审计待支付的订单
-        $this->detectOrders();
-
-        // 关闭超时未支付订单
-        $this->closeOrders();
-
-        // 关闭超过72小时未处理的工单
-        $this->closeTickets();
-
-        // 检测节点是否离线
-        $this->checkNodeStatus();
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
-
-    // 注册验证码自动置无效
-    private function expireVerifyCode()
-    {
-        VerifyCode::query()->where('status', 0)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-10 minutes")))->update(['status' => 2]);
-    }
-
-    // 优惠券到期自动置无效
-    private function expireCoupon()
-    {
-        $couponList = Coupon::query()->where('status', 0)->where('available_end', '<=', time())->get();
-        if (!$couponList->isEmpty()) {
-            foreach ($couponList as $coupon) {
-                Coupon::query()->where('id', $coupon->id)->update(['status' => 2]);
-            }
-        }
-    }
-
-    // 邀请码到期自动置无效
-    private function expireInvite()
-    {
-        $inviteList = Invite::query()->where('status', 0)->where('dateline', '<=', date('Y-m-d H:i:s'))->get();
-        if (!$inviteList->isEmpty()) {
-            foreach ($inviteList as $invite) {
-                Invite::query()->where('id', $invite->id)->update(['status' => 2]);
-            }
-        }
-    }
-
-    // 封禁访问异常的订阅链接
-    private function blockSubscribe()
-    {
-        if (self::$systemConfig['is_subscribe_ban']) {
-            $subscribeList = UserSubscribe::query()->where('status', 1)->get();
-            if (!$subscribeList->isEmpty()) {
-                foreach ($subscribeList as $subscribe) {
-                    // 24小时内不同IP的请求次数
-                    $request_times = UserSubscribeLog::query()->where('sid', $subscribe->id)->where('request_time', '>=', date("Y-m-d H:i:s", strtotime("-24 hours")))->distinct('request_ip')->count('request_ip');
-                    if ($request_times >= self::$systemConfig['subscribe_ban_times']) {
-                        UserSubscribe::query()->where('id', $subscribe->id)->update(['status' => 0, 'ban_time' => time(), 'ban_desc' => '存在异常,自动封禁']);
-
-                        // 记录封禁日志
-                        $this->addUserBanLog($subscribe->user_id, 0, '【完全封禁订阅】-订阅24小时内请求异常');
-                    }
-                }
-            }
-        }
-    }
-
-    // 封禁账号
-    private function blockUsers()
-    {
-        // 过期用户处理
-        $userList = User::query()->where('status', '>=', 0)->where('enable', 1)->where('expire_time', '<', date('Y-m-d'))->get();
-        if (!$userList->isEmpty()) {
-            foreach ($userList as $user) {
-                if (self::$systemConfig['is_ban_status']) {
-                    User::query()->where('id', $user->id)->update([
-                        'u'                 => 0,
-                        'd'                 => 0,
-                        'transfer_enable'   => 0,
-                        'enable'            => 0,
-                        'traffic_reset_day' => 0,
-                        'ban_time'          => 0,
-                        'status'            => -1
-                    ]);
-
-                    $this->addUserBanLog($user->id, 0, '【禁止登录,清空账户】-账号已过期');
-
-                    // 如果注册就有初始流量,则废除其名下邀请码
-                    if (self::$systemConfig['default_traffic']) {
-                        Invite::query()->where('uid', $user->id)->where('status', 0)->update(['status' => 2]);
-                    }
-
-                    // 写入用户流量变动记录
-                    Helpers::addUserTrafficModifyLog($user->id, 0, $user->transfer_enable, 0, '[定时任务]账号已过期(禁止登录,清空账户)');
-                } else {
-                    User::query()->where('id', $user->id)->update([
-                        'u'                 => 0,
-                        'd'                 => 0,
-                        'transfer_enable'   => 0,
-                        'enable'            => 0,
-                        'traffic_reset_day' => 0,
-                        'ban_time'          => 0
-                    ]);
-
-                    $this->addUserBanLog($user->id, 0, '【封禁代理,清空账户】-账号已过期');
-
-                    // 写入用户流量变动记录
-                    Helpers::addUserTrafficModifyLog($user->id, 0, $user->transfer_enable, 0, '[定时任务]账号已过期(封禁代理,清空账户)');
-                }
-
-                // 移除标签
-                UserLabel::query()->where('user_id', $user->id)->delete();
-            }
-        }
-
-        // 封禁1小时内流量异常账号
-        if (self::$systemConfig['is_traffic_ban']) {
-            $userList = User::query()->where('status', '>=', 0)->where('enable', 1)->where('ban_time', 0)->get();
-            if (!$userList->isEmpty()) {
-                foreach ($userList as $user) {
-                    // 对管理员豁免
-                    if ($user->is_admin) {
-                        continue;
-                    }
-
-                    // 多往前取5分钟,防止数据统计任务执行时间过长导致没有数据
-                    $totalTraffic = UserTrafficHourly::query()->where('user_id', $user->id)->where('node_id', 0)->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))->sum('total');
-                    if ($totalTraffic >= (self::$systemConfig['traffic_ban_value'] * 1073741824)) {
-                        User::query()->where('id', $user->id)->update(['enable' => 0, 'ban_time' => strtotime(date('Y-m-d H:i:s', strtotime("+" . self::$systemConfig['traffic_ban_time'] . " minutes")))]);
-
-                        // 写入日志
-                        $this->addUserBanLog($user->id, self::$systemConfig['traffic_ban_time'], '【临时封禁代理】-1小时内流量异常');
-                    }
-                }
-            }
-        }
-
-        // 禁用流量超限用户
-        $userList = User::query()->where('status', '>=', 0)->where('enable', 1)->where('ban_time', 0)->whereRaw("u + d >= transfer_enable")->get();
-        if (!$userList->isEmpty()) {
-            foreach ($userList as $user) {
-                User::query()->where('id', $user->id)->update(['enable' => 0]);
-
-                // 写入日志
-                $this->addUserBanLog($user->id, 0, '【封禁代理】-流量已用完');
-            }
-        }
-    }
-
-    // 解封被临时封禁的账号
-    private function unblockUsers()
-    {
-        // 解封被临时封禁的账号
-        $userList = User::query()->where('status', '>=', 0)->where('enable', 0)->where('ban_time', '>', 0)->get();
-        foreach ($userList as $user) {
-            if ($user->ban_time < time()) {
-                User::query()->where('id', $user->id)->update(['enable' => 1, 'ban_time' => 0]);
-
-                // 写入操作日志
-                $this->addUserBanLog($user->id, 0, '【自动解封】-临时封禁到期');
-            }
-        }
-
-        // 可用流量大于已用流量也解封(比如:邀请返利自动加了流量)
-        $userList = User::query()->where('status', '>=', 0)->where('enable', 0)->where('ban_time', 0)->where('expire_time', '>=', date('Y-m-d'))->whereRaw("u + d < transfer_enable")->get();
-        if (!$userList->isEmpty()) {
-            foreach ($userList as $user) {
-                User::query()->where('id', $user->id)->update(['enable' => 1]);
-
-                // 写入操作日志
-                $this->addUserBanLog($user->id, 0, '【自动解封】-有流量解封');
-            }
-        }
-    }
-
-    // 端口回收与分配
-    private function dispatchPort()
-    {
-        if (self::$systemConfig['auto_release_port']) {
-            ## 自动分配端口
-            $userList = User::query()->where('status', '>=', 0)->where('enable', 1)->where('port', 0)->get();
-            if (!$userList->isEmpty()) {
-                foreach ($userList as $user) {
-                    $port = self::$systemConfig['is_rand_port'] ? Helpers::getRandPort() : Helpers::getOnlyPort();
-
-                    User::query()->where('id', $user->id)->update(['port' => $port]);
-                }
-            }
-
-            ## 被封禁的账号自动释放端口
-            $userList = User::query()->where('status', -1)->where('enable', 0)->get();
-            if (!$userList->isEmpty()) {
-                foreach ($userList as $user) {
-                    if ($user->port) {
-                        User::query()->where('id', $user->id)->update(['port' => 0]);
-                    }
-                }
-            }
-
-            ## 过期一个月的账户自动释放端口
-            $userList = User::query()->where('enable', 0)->get();
-            if (!$userList->isEmpty()) {
-                foreach ($userList as $user) {
-                    if ($user->port) {
-                        $overdueDays = floor((strtotime(date('Y-m-d H:i:s')) - strtotime($user->expire_time)) / 86400);
-                        if ($overdueDays > 30) {
-                            User::query()->where('id', $user->id)->update(['port' => 0]);
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    // 审计待支付的订单
-    private function detectOrders()
-    {
-        /*
-         * 因为订单在15分钟未支付则会被自动关闭
-         * 当有赞没有正常推送消息或者其他原因导致用户已付款但是订单不生效从而导致用户无法正常加流量、置状态
-         * 故需要每分钟请求一次未支付订单,审计一下其支付状态
-         */
-        $paymentList = Payment::query()->with(['order', 'user'])->where('status', 0)->where('qr_id', '>', 0)->get();
-        if (!$paymentList->isEmpty()) {
-            foreach ($paymentList as $payment) {
-                // 跳过order丢失的订单
-                if (!isset($payment->order)) {
-                    continue;
-                }
-
-                $yzy = new yzy();
-                $trade = $yzy->getTradeByQrId($payment->qr_id);
-                if ($trade['response']['total_results']) {
-                    // 再判断一遍当前要操作的订单的状态是否被改变了(可能请求延迟的时候已经回调处理完了)
-                    $payment = Payment::query()->where('id', $payment->id)->first();
-                    if ($payment->status != '0') {
-                        continue;
-                    }
-
-                    // 处理订单
-                    DB::beginTransaction();
-                    try {
-                        // 如果支付单中没有用户信息则创建一个用户
-                        if (!$payment->user_id) {
-                            // 生成一个可用端口
-                            $port = self::$systemConfig['is_rand_port'] ? Helpers::getRandPort() : Helpers::getOnlyPort();
-
-                            $user = new User();
-                            $user->username = '自动生成-' . $payment->order->email;
-                            $user->password = md5(makeRandStr());
-                            $user->port = $port;
-                            $user->passwd = makeRandStr();
-                            $user->vmess_id = createGuid();
-                            $user->enable = 1;
-                            $user->method = Helpers::getDefaultMethod();
-                            $user->protocol = Helpers::getDefaultProtocol();
-                            $user->obfs = Helpers::getDefaultObfs();
-                            $user->usage = 1;
-                            $user->transfer_enable = 1; // 新创建的账号给1,防止定时任务执行时发现u + d >= transfer_enable被判为流量超限而封禁
-                            $user->enable_time = date('Y-m-d');
-                            $user->expire_time = date('Y-m-d', strtotime("+" . $payment->order->goods->days . " days"));
-                            $user->reg_ip = getClientIp();
-                            $user->referral_uid = 0;
-                            $user->traffic_reset_day = 0;
-                            $user->status = 1;
-                            $user->save();
-
-                            if ($user->id) {
-                                Order::query()->where('oid', $payment->oid)->update(['user_id' => $user->id]);
-                            }
-                        }
-
-                        // 更新支付单
-                        $payment->pay_way = $trade['response']['pay_type'] == 'WXPAY_BIGUNSIGN' ? 1 : 2; // 1-微信、2-支付宝
-                        $payment->status = 1;
-                        $payment->save();
-
-                        // 更新订单
-                        $order = Order::query()->with(['user'])->where('oid', $payment->oid)->first();
-                        $order->status = 2;
-                        $order->save();
-
-                        $goods = Goods::query()->where('id', $order->goods_id)->first();
-
-                        // 商品为流量或者套餐
-                        if ($goods->type <= 2) {
-                            // 如果买的是套餐,则先将之前购买的所有套餐置都无效,并扣掉之前所有套餐的流量,重置用户已用流量为0
-                            if ($goods->type == 2) {
-                                $existOrderList = Order::query()
-                                    ->with(['goods'])
-                                    ->whereHas('goods', function ($q) {
-                                        $q->where('type', 2);
-                                    })
-                                    ->where('user_id', $order->user_id)
-                                    ->where('oid', '<>', $order->oid)
-                                    ->where('is_expire', 0)
-                                    ->where('status', 2)
-                                    ->get();
-
-                                foreach ($existOrderList as $vo) {
-                                    Order::query()->where('oid', $vo->oid)->update(['is_expire' => 1]);
-
-                                    // 先判断,防止手动扣减过流量的用户流量被扣成负数
-                                    if ($order->user->transfer_enable - $vo->goods->traffic * 1048576 <= 0) {
-                                        // 写入用户流量变动记录
-                                        Helpers::addUserTrafficModifyLog($order->user_id, 0, $order->user->transfer_enable, 0, '[定时任务]审计待支付的订单(扣完)');
-
-                                        User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
-                                    } else {
-                                        // 写入用户流量变动记录
-                                        Helpers::addUserTrafficModifyLog($order->user_id, 0, $order->user->transfer_enable, ($order->user->transfer_enable - $vo->goods->traffic * 1048576), '[定时任务]审计待支付的订单');
-
-                                        User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0]);
-                                        User::query()->where('id', $order->user_id)->decrement('transfer_enable', $vo->goods->traffic * 1048576);
-                                    }
-                                }
-                            }
-
-                            // 计算账号过期时间
-                            if ($order->user->expire_time < date('Y-m-d', strtotime("+" . $goods->days . " days"))) {
-                                $expireTime = date('Y-m-d', strtotime("+" . $goods->days . " days"));
-                            } else {
-                                $expireTime = $order->user->expire_time;
-                            }
-
-                            // 把商品的流量加到账号上
-                            User::query()->where('id', $order->user_id)->increment('transfer_enable', $goods->traffic * 1048576);
-
-                            // 套餐就改流量重置日,流量包不改
-                            if ($goods->type == 2) {
-                                if (date('m') == 2 && date('d') == 29) {
-                                    $traffic_reset_day = 28;
-                                } else {
-                                    $traffic_reset_day = date('d') == 31 ? 30 : abs(date('d'));
-                                }
-
-                                User::query()->where('id', $order->user_id)->update(['traffic_reset_day' => $traffic_reset_day, 'expire_time' => $expireTime, 'enable' => 1]);
-                            } else {
-                                User::query()->where('id', $order->user_id)->update(['expire_time' => $expireTime, 'enable' => 1]);
-                            }
-
-                            // 写入用户标签
-                            if ($goods->label) {
-                                // 用户默认标签
-                                $defaultLabels = [];
-                                if (self::$systemConfig['initial_labels_for_user']) {
-                                    $defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
-                                }
-
-                                // 取出现有的标签
-                                $userLabels = UserLabel::query()->where('user_id', $order->user_id)->pluck('label_id')->toArray();
-                                $goodsLabels = GoodsLabel::query()->where('goods_id', $order->goods_id)->pluck('label_id')->toArray();
-
-                                // 标签去重
-                                $newUserLabels = array_values(array_unique(array_merge($userLabels, $goodsLabels, $defaultLabels)));
-
-                                // 删除用户所有标签
-                                UserLabel::query()->where('user_id', $order->user_id)->delete();
-
-                                // 生成标签
-                                foreach ($newUserLabels as $vo) {
-                                    $obj = new UserLabel();
-                                    $obj->user_id = $order->user_id;
-                                    $obj->label_id = $vo;
-                                    $obj->save();
-                                }
-                            }
-
-                            // 写入返利日志
-                            if ($order->user->referral_uid) {
-                                $this->addReferralLog($order->user_id, $order->user->referral_uid, $order->oid, $order->amount, $order->amount * self::$systemConfig['referral_percent']);
-                            }
-
-                            // 取消重复返利
-                            User::query()->where('id', $order->user_id)->update(['referral_uid' => 0]);
-
-                        } elseif ($goods->type == 3) { // 商品为在线充值
-                            User::query()->where('id', $order->user_id)->increment('balance', $goods->price * 100);
-
-                            // 余额变动记录日志
-                            $this->addUserBalanceLog($order->user_id, $order->oid, $order->user->balance, $order->user->balance + $goods->price, $goods->price, '用户在线充值');
-                        }
-
-                        // 自动提号机:如果order的email值不为空
-                        if ($order->email) {
-                            $title = '【' . self::$systemConfig['website_name'] . '】您的账号信息';
-                            $content = [
-                                'order_sn'      => $order->order_sn,
-                                'goods_name'    => $order->goods->name,
-                                'goods_traffic' => flowAutoShow($order->goods->traffic * 1048576),
-                                'port'          => $order->user->port,
-                                'passwd'        => $order->user->passwd,
-                                'method'        => $order->user->method,
-                                //'protocol'       => $order->user->protocol,
-                                //'protocol_param' => $order->user->protocol_param,
-                                //'obfs'           => $order->user->obfs,
-                                //'obfs_param'     => $order->user->obfs_param,
-                                'created_at'    => $order->created_at->toDateTimeString(),
-                                'expire_at'     => $order->expire_at
-                            ];
-
-                            // 获取可用节点列表
-                            $labels = UserLabel::query()->where('user_id', $order->user_id)->get()->pluck('label_id');
-                            $nodeIds = SsNodeLabel::query()->whereIn('label_id', $labels)->get()->pluck('node_id');
-                            $nodeList = SsNode::query()->whereIn('id', $nodeIds)->orderBy('sort', 'desc')->orderBy('id', 'desc')->get()->toArray();
-                            $content['serverList'] = $nodeList;
-
-                            $logId = Helpers::addEmailLog($order->email, $title, json_encode($content));
-                            Mail::to($order->email)->send(new sendUserInfo($logId, $content));
-                        }
-
-                        DB::commit();
-                    } catch (\Exception $e) {
-                        DB::rollBack();
-
-                        Log::info('【有赞云】审计订单时更新支付单和订单异常:' . $e);
-                    }
-                }
-            }
-        }
-    }
-
-    // 关闭超时未支付订单
-    private function closeOrders()
-    {
-        // 关闭超时未支付的有赞云订单(有赞云收款二维码超过30分钟自动关闭,关闭后无法再支付,所以我们限制15分钟内必须付款)
-        $paymentList = Payment::query()->with(['order', 'order.coupon'])->where('status', 0)->where('created_at', '<=', date("Y-m-d H:i:s", strtotime("-15 minutes")))->get();
-        if (!$paymentList->isEmpty()) {
-            DB::beginTransaction();
-            try {
-                foreach ($paymentList as $payment) {
-                    // 关闭支付单
-                    Payment::query()->where('id', $payment->id)->update(['status' => -1]);
-
-                    // 关闭订单
-                    Order::query()->where('oid', $payment->oid)->update(['status' => -1]);
-
-                    // 退回优惠券
-                    if ($payment->order->coupon_id) {
-                        Coupon::query()->where('id', $payment->order->coupon_id)->update(['status' => 0]);
-
-                        Helpers::addCouponLog($payment->order->coupon_id, $payment->order->goods_id, $payment->oid, '订单超时未支付,自动退回');
-                    }
-                }
-
-                DB::commit();
-            } catch (\Exception $e) {
-                Log::info('【异常】自动关闭超时未支付订单:' . $e);
-
-                DB::rollBack();
-            }
-        }
-    }
-
-    // 关闭超过72小时未处理的工单
-    private function closeTickets()
-    {
-        $ticketList = Ticket::query()->where('updated_at', '<=', date('Y-m-d H:i:s', strtotime("-72 hours")))->where('status', 1)->get();
-        foreach ($ticketList as $ticket) {
-            $ret = Ticket::query()->where('id', $ticket->id)->update(['status' => 2]);
-            if ($ret) {
-                ServerChan::send('工单关闭提醒', '工单:ID' . $ticket->id . '超过72小时未处理,系统已自动关闭');
-            }
-        }
-    }
-
-    // 检测节点是否离线
-    private function checkNodeStatus()
-    {
-        if (Helpers::systemConfig()['is_node_crash_warning']) {
-            $nodeList = SsNode::query()->where('is_transit', 0)->where('status', 1)->get();
-            foreach ($nodeList as $node) {
-                // 10分钟内无节点负载信息且TCP检测认为不是离线则认为是后端炸了
-                $nodeTTL = SsNodeInfo::query()->where('node_id', $node->id)->where('log_time', '>=', strtotime("-10 minutes"))->orderBy('id', 'desc')->first();
-                if (!$nodeTTL) {
-                    ServerChan::send('节点异常警告', "节点**{$node->name}【{$node->ip}】**异常:**心跳异常,可能离线了**");
-                }
-            }
-        }
-    }
-
-    /**
-     * 添加用户封禁日志
-     *
-     * @param int    $userId  用户ID
-     * @param int    $minutes 封禁时长,单位分钟
-     * @param string $desc    封禁理由
-     */
-    private function addUserBanLog($userId, $minutes, $desc)
-    {
-        $log = new UserBanLog();
-        $log->user_id = $userId;
-        $log->minutes = $minutes;
-        $log->desc = $desc;
-        $log->save();
-    }
-
-    /**
-     * 添加返利日志
-     *
-     * @param int $userId    用户ID
-     * @param int $refUserId 返利用户ID
-     * @param int $oid       订单ID
-     * @param int $amount    发生金额
-     * @param int $refAmount 返利金额
-     *
-     * @return int
-     */
-    public function addReferralLog($userId, $refUserId, $oid, $amount, $refAmount)
-    {
-        $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();
-    }
-
-    /**
-     * 记录余额操作日志
-     *
-     * @param int    $userId 用户ID
-     * @param string $oid    订单ID
-     * @param int    $before 记录前余额
-     * @param int    $after  记录后余额
-     * @param int    $amount 发生金额
-     * @param string $desc   描述
-     *
-     * @return int
-     */
-    public function addUserBalanceLog($userId, $oid, $before, $after, $amount, $desc = '')
-    {
-        $log = new UserBalanceLog();
-        $log->user_id = $userId;
-        $log->order_id = $oid;
-        $log->before = $before;
-        $log->after = $after;
-        $log->amount = $amount;
-        $log->desc = $desc;
-        $log->created_at = date('Y-m-d H:i:s');
-
-        return $log->save();
-    }
+	protected $signature = 'autoJob';
+	protected $description = '自动化任务';
+	protected static $systemConfig;
+
+	public function __construct()
+	{
+		parent::__construct();
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	/*
+	 * 警告:除非熟悉业务流程,否则不推荐更改以下执行顺序,随意变更以下顺序可能导致系统异常
+	 */
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
+
+		// 注册验证码自动置无效
+		$this->expireVerifyCode();
+
+		// 优惠券到期自动置无效
+		$this->expireCoupon();
+
+		// 邀请码到期自动置无效
+		$this->expireInvite();
+
+		// 封禁访问异常的订阅链接
+		$this->blockSubscribe();
+
+		// 封禁账号
+		$this->blockUsers();
+
+		// 解封被封禁的账号
+		$this->unblockUsers();
+
+		// 端口回收与分配
+		$this->dispatchPort();
+
+		// 审计待支付的订单
+		$this->detectOrders();
+
+		// 关闭超时未支付订单
+		$this->closeOrders();
+
+		// 关闭超过72小时未处理的工单
+		$this->closeTickets();
+
+		// 检测节点是否离线
+		$this->checkNodeStatus();
+
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
+
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
+
+	// 注册验证码自动置无效
+	private function expireVerifyCode()
+	{
+		VerifyCode::query()->where('status', 0)->where('created_at', '<=', date('Y-m-d H:i:s', strtotime("-10 minutes")))->update(['status' => 2]);
+	}
+
+	// 优惠券到期自动置无效
+	private function expireCoupon()
+	{
+		$couponList = Coupon::query()->where('status', 0)->where('available_end', '<=', time())->get();
+		if(!$couponList->isEmpty()){
+			foreach($couponList as $coupon){
+				Coupon::query()->where('id', $coupon->id)->update(['status' => 2]);
+			}
+		}
+	}
+
+	// 邀请码到期自动置无效
+	private function expireInvite()
+	{
+		$inviteList = Invite::query()->where('status', 0)->where('dateline', '<=', date('Y-m-d H:i:s'))->get();
+		if(!$inviteList->isEmpty()){
+			foreach($inviteList as $invite){
+				Invite::query()->where('id', $invite->id)->update(['status' => 2]);
+			}
+		}
+	}
+
+	// 封禁访问异常的订阅链接
+	private function blockSubscribe()
+	{
+		if(self::$systemConfig['is_subscribe_ban']){
+			$subscribeList = UserSubscribe::query()->where('status', 1)->get();
+			if(!$subscribeList->isEmpty()){
+				foreach($subscribeList as $subscribe){
+					// 24小时内不同IP的请求次数
+					$request_times = UserSubscribeLog::query()->where('sid', $subscribe->id)->where('request_time', '>=', date("Y-m-d H:i:s", strtotime("-24 hours")))->distinct('request_ip')->count('request_ip');
+					if($request_times >= self::$systemConfig['subscribe_ban_times']){
+						UserSubscribe::query()->where('id', $subscribe->id)->update(['status' => 0, 'ban_time' => time(), 'ban_desc' => '存在异常,自动封禁']);
+
+						// 记录封禁日志
+						$this->addUserBanLog($subscribe->user_id, 0, '【完全封禁订阅】-订阅24小时内请求异常');
+					}
+				}
+			}
+		}
+	}
+
+	// 封禁账号
+	private function blockUsers()
+	{
+		// 过期用户处理
+		$userList = User::query()->where('status', '>=', 0)->where('enable', 1)->where('expire_time', '<', date('Y-m-d'))->get();
+		if(!$userList->isEmpty()){
+			foreach($userList as $user){
+				if(self::$systemConfig['is_ban_status']){
+					User::query()->where('id', $user->id)->update([
+						'u'                 => 0,
+						'd'                 => 0,
+						'transfer_enable'   => 0,
+						'enable'            => 0,
+						'traffic_reset_day' => 0,
+						'ban_time'          => 0,
+						'status'            => -1
+					]);
+
+					$this->addUserBanLog($user->id, 0, '【禁止登录,清空账户】-账号已过期');
+
+					// 如果注册就有初始流量,则废除其名下邀请码
+					if(self::$systemConfig['default_traffic']){
+						Invite::query()->where('uid', $user->id)->where('status', 0)->update(['status' => 2]);
+					}
+
+					// 写入用户流量变动记录
+					Helpers::addUserTrafficModifyLog($user->id, 0, $user->transfer_enable, 0, '[定时任务]账号已过期(禁止登录,清空账户)');
+				}else{
+					User::query()->where('id', $user->id)->update([
+						'u'                 => 0,
+						'd'                 => 0,
+						'transfer_enable'   => 0,
+						'enable'            => 0,
+						'traffic_reset_day' => 0,
+						'ban_time'          => 0
+					]);
+
+					$this->addUserBanLog($user->id, 0, '【封禁代理,清空账户】-账号已过期');
+
+					// 写入用户流量变动记录
+					Helpers::addUserTrafficModifyLog($user->id, 0, $user->transfer_enable, 0, '[定时任务]账号已过期(封禁代理,清空账户)');
+				}
+
+				// 移除标签
+				UserLabel::query()->where('user_id', $user->id)->delete();
+			}
+		}
+
+		// 封禁1小时内流量异常账号
+		if(self::$systemConfig['is_traffic_ban']){
+			$userList = User::query()->where('status', '>=', 0)->where('enable', 1)->where('ban_time', 0)->get();
+			if(!$userList->isEmpty()){
+				foreach($userList as $user){
+					// 对管理员豁免
+					if($user->is_admin){
+						continue;
+					}
+
+					// 多往前取5分钟,防止数据统计任务执行时间过长导致没有数据
+					$totalTraffic = UserTrafficHourly::query()->where('user_id', $user->id)->where('node_id', 0)->where('created_at', '>=', date('Y-m-d H:i:s', time()-3900))->sum('total');
+					if($totalTraffic >= (self::$systemConfig['traffic_ban_value']*1073741824)){
+						User::query()->where('id', $user->id)->update(['enable' => 0, 'ban_time' => strtotime(date('Y-m-d H:i:s', strtotime("+".self::$systemConfig['traffic_ban_time']." minutes")))]);
+
+						// 写入日志
+						$this->addUserBanLog($user->id, self::$systemConfig['traffic_ban_time'], '【临时封禁代理】-1小时内流量异常');
+					}
+				}
+			}
+		}
+
+		// 禁用流量超限用户
+		$userList = User::query()->where('status', '>=', 0)->where('enable', 1)->where('ban_time', 0)->whereRaw("u + d >= transfer_enable")->get();
+		if(!$userList->isEmpty()){
+			foreach($userList as $user){
+				User::query()->where('id', $user->id)->update(['enable' => 0]);
+
+				// 写入日志
+				$this->addUserBanLog($user->id, 0, '【封禁代理】-流量已用完');
+			}
+		}
+	}
+
+	// 解封被临时封禁的账号
+	private function unblockUsers()
+	{
+		// 解封被临时封禁的账号
+		$userList = User::query()->where('status', '>=', 0)->where('enable', 0)->where('ban_time', '>', 0)->get();
+		foreach($userList as $user){
+			if($user->ban_time < time()){
+				User::query()->where('id', $user->id)->update(['enable' => 1, 'ban_time' => 0]);
+
+				// 写入操作日志
+				$this->addUserBanLog($user->id, 0, '【自动解封】-临时封禁到期');
+			}
+		}
+
+		// 可用流量大于已用流量也解封(比如:邀请返利自动加了流量)
+		$userList = User::query()->where('status', '>=', 0)->where('enable', 0)->where('ban_time', 0)->where('expire_time', '>=', date('Y-m-d'))->whereRaw("u + d < transfer_enable")->get();
+		if(!$userList->isEmpty()){
+			foreach($userList as $user){
+				User::query()->where('id', $user->id)->update(['enable' => 1]);
+
+				// 写入操作日志
+				$this->addUserBanLog($user->id, 0, '【自动解封】-有流量解封');
+			}
+		}
+	}
+
+	// 端口回收与分配
+	private function dispatchPort()
+	{
+		if(self::$systemConfig['auto_release_port']){
+			## 自动分配端口
+			$userList = User::query()->where('status', '>=', 0)->where('enable', 1)->where('port', 0)->get();
+			if(!$userList->isEmpty()){
+				foreach($userList as $user){
+					$port = self::$systemConfig['is_rand_port']? Helpers::getRandPort() : Helpers::getOnlyPort();
+
+					User::query()->where('id', $user->id)->update(['port' => $port]);
+				}
+			}
+
+			## 被封禁的账号自动释放端口
+			$userList = User::query()->where('status', -1)->where('enable', 0)->get();
+			if(!$userList->isEmpty()){
+				foreach($userList as $user){
+					if($user->port){
+						User::query()->where('id', $user->id)->update(['port' => 0]);
+					}
+				}
+			}
+
+			## 过期一个月的账户自动释放端口
+			$userList = User::query()->where('enable', 0)->get();
+			if(!$userList->isEmpty()){
+				foreach($userList as $user){
+					if($user->port){
+						$overdueDays = floor((strtotime(date('Y-m-d H:i:s'))-strtotime($user->expire_time))/86400);
+						if($overdueDays > 30){
+							User::query()->where('id', $user->id)->update(['port' => 0]);
+						}
+					}
+				}
+			}
+		}
+	}
+
+	// 审计待支付的订单
+	private function detectOrders()
+	{
+		/*
+		 * 因为订单在15分钟未支付则会被自动关闭
+		 * 当有赞没有正常推送消息或者其他原因导致用户已付款但是订单不生效从而导致用户无法正常加流量、置状态
+		 * 故需要每分钟请求一次未支付订单,审计一下其支付状态
+		 */
+		$paymentList = Payment::query()->with(['order', 'user'])->where('status', 0)->where('qr_id', '>', 0)->get();
+		if(!$paymentList->isEmpty()){
+			foreach($paymentList as $payment){
+				// 跳过order丢失的订单
+				if(!isset($payment->order)){
+					continue;
+				}
+
+				$yzy = new yzy();
+				$trade = $yzy->getTradeByQrId($payment->qr_id);
+				if($trade['response']['total_results']){
+					// 再判断一遍当前要操作的订单的状态是否被改变了(可能请求延迟的时候已经回调处理完了)
+					$payment = Payment::query()->where('id', $payment->id)->first();
+					if($payment->status != '0'){
+						continue;
+					}
+
+					// 处理订单
+					DB::beginTransaction();
+					try{
+						// 如果支付单中没有用户信息则创建一个用户
+						if(!$payment->user_id){
+							// 生成一个可用端口
+							$port = self::$systemConfig['is_rand_port']? Helpers::getRandPort() : Helpers::getOnlyPort();
+
+							$user = new User();
+							$user->username = '自动生成-'.$payment->order->email;
+							$user->password = md5(makeRandStr());
+							$user->port = $port;
+							$user->passwd = makeRandStr();
+							$user->vmess_id = createGuid();
+							$user->enable = 1;
+							$user->method = Helpers::getDefaultMethod();
+							$user->protocol = Helpers::getDefaultProtocol();
+							$user->obfs = Helpers::getDefaultObfs();
+							$user->usage = 1;
+							$user->transfer_enable = 1; // 新创建的账号给1,防止定时任务执行时发现u + d >= transfer_enable被判为流量超限而封禁
+							$user->enable_time = date('Y-m-d');
+							$user->expire_time = date('Y-m-d', strtotime("+".$payment->order->goods->days." days"));
+							$user->reg_ip = getClientIp();
+							$user->referral_uid = 0;
+							$user->traffic_reset_day = 0;
+							$user->status = 1;
+							$user->save();
+
+							if($user->id){
+								Order::query()->where('oid', $payment->oid)->update(['user_id' => $user->id]);
+							}
+						}
+
+						// 更新支付单
+						$payment->pay_way = $trade['response']['pay_type'] == 'WXPAY_BIGUNSIGN'? 1 : 2; // 1-微信、2-支付宝
+						$payment->status = 1;
+						$payment->save();
+
+						// 更新订单
+						$order = Order::query()->with(['user'])->where('oid', $payment->oid)->first();
+						$order->status = 2;
+						$order->save();
+
+						$goods = Goods::query()->where('id', $order->goods_id)->first();
+
+						// 商品为流量或者套餐
+						if($goods->type <= 2){
+							// 如果买的是套餐,则先将之前购买的所有套餐置都无效,并扣掉之前所有套餐的流量,重置用户已用流量为0
+							if($goods->type == 2){
+								$existOrderList = Order::query()
+									->with(['goods'])
+									->whereHas('goods', function($q){
+										$q->where('type', 2);
+									})
+									->where('user_id', $order->user_id)
+									->where('oid', '<>', $order->oid)
+									->where('is_expire', 0)
+									->where('status', 2)
+									->get();
+
+								foreach($existOrderList as $vo){
+									Order::query()->where('oid', $vo->oid)->update(['is_expire' => 1]);
+
+									// 先判断,防止手动扣减过流量的用户流量被扣成负数
+									if($order->user->transfer_enable-$vo->goods->traffic*1048576 <= 0){
+										// 写入用户流量变动记录
+										Helpers::addUserTrafficModifyLog($order->user_id, 0, $order->user->transfer_enable, 0, '[定时任务]审计待支付的订单(扣完)');
+
+										User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
+									}else{
+										// 写入用户流量变动记录
+										Helpers::addUserTrafficModifyLog($order->user_id, 0, $order->user->transfer_enable, ($order->user->transfer_enable-$vo->goods->traffic*1048576), '[定时任务]审计待支付的订单');
+
+										User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0]);
+										User::query()->where('id', $order->user_id)->decrement('transfer_enable', $vo->goods->traffic*1048576);
+									}
+								}
+							}
+
+							// 计算账号过期时间
+							if($order->user->expire_time < date('Y-m-d', strtotime("+".$goods->days." days"))){
+								$expireTime = date('Y-m-d', strtotime("+".$goods->days." days"));
+							}else{
+								$expireTime = $order->user->expire_time;
+							}
+
+							// 把商品的流量加到账号上
+							User::query()->where('id', $order->user_id)->increment('transfer_enable', $goods->traffic*1048576);
+
+							// 套餐就改流量重置日,流量包不改
+							if($goods->type == 2){
+								if(date('m') == 2 && date('d') == 29){
+									$traffic_reset_day = 28;
+								}else{
+									$traffic_reset_day = date('d') == 31? 30 : abs(date('d'));
+								}
+
+								User::query()->where('id', $order->user_id)->update(['traffic_reset_day' => $traffic_reset_day, 'expire_time' => $expireTime, 'enable' => 1]);
+							}else{
+								User::query()->where('id', $order->user_id)->update(['expire_time' => $expireTime, 'enable' => 1]);
+							}
+
+							// 写入用户标签
+							if($goods->label){
+								// 用户默认标签
+								$defaultLabels = [];
+								if(self::$systemConfig['initial_labels_for_user']){
+									$defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
+								}
+
+								// 取出现有的标签
+								$userLabels = UserLabel::query()->where('user_id', $order->user_id)->pluck('label_id')->toArray();
+								$goodsLabels = GoodsLabel::query()->where('goods_id', $order->goods_id)->pluck('label_id')->toArray();
+
+								// 标签去重
+								$newUserLabels = array_values(array_unique(array_merge($userLabels, $goodsLabels, $defaultLabels)));
+
+								// 删除用户所有标签
+								UserLabel::query()->where('user_id', $order->user_id)->delete();
+
+								// 生成标签
+								foreach($newUserLabels as $vo){
+									$obj = new UserLabel();
+									$obj->user_id = $order->user_id;
+									$obj->label_id = $vo;
+									$obj->save();
+								}
+							}
+
+							// 写入返利日志
+							if($order->user->referral_uid){
+								$this->addReferralLog($order->user_id, $order->user->referral_uid, $order->oid, $order->amount, $order->amount*self::$systemConfig['referral_percent']);
+							}
+
+							// 取消重复返利
+							User::query()->where('id', $order->user_id)->update(['referral_uid' => 0]);
+
+						}elseif($goods->type == 3){ // 商品为在线充值
+							User::query()->where('id', $order->user_id)->increment('balance', $goods->price*100);
+
+							// 余额变动记录日志
+							$this->addUserBalanceLog($order->user_id, $order->oid, $order->user->balance, $order->user->balance+$goods->price, $goods->price, '用户在线充值');
+						}
+
+						// 自动提号机:如果order的email值不为空
+						if($order->email){
+							$title = '【'.self::$systemConfig['website_name'].'】您的账号信息';
+							$content = [
+								'order_sn'      => $order->order_sn,
+								'goods_name'    => $order->goods->name,
+								'goods_traffic' => flowAutoShow($order->goods->traffic*1048576),
+								'port'          => $order->user->port,
+								'passwd'        => $order->user->passwd,
+								'method'        => $order->user->method,
+								//'protocol'       => $order->user->protocol,
+								//'protocol_param' => $order->user->protocol_param,
+								//'obfs'           => $order->user->obfs,
+								//'obfs_param'     => $order->user->obfs_param,
+								'created_at'    => $order->created_at->toDateTimeString(),
+								'expire_at'     => $order->expire_at
+							];
+
+							// 获取可用节点列表
+							$labels = UserLabel::query()->where('user_id', $order->user_id)->get()->pluck('label_id');
+							$nodeIds = SsNodeLabel::query()->whereIn('label_id', $labels)->get()->pluck('node_id');
+							$nodeList = SsNode::query()->whereIn('id', $nodeIds)->orderBy('sort', 'desc')->orderBy('id', 'desc')->get()->toArray();
+							$content['serverList'] = $nodeList;
+
+							$logId = Helpers::addEmailLog($order->email, $title, json_encode($content));
+							Mail::to($order->email)->send(new sendUserInfo($logId, $content));
+						}
+
+						DB::commit();
+					} catch(Exception $e){
+						DB::rollBack();
+
+						Log::info('【有赞云】审计订单时更新支付单和订单异常:'.$e);
+					}
+				}
+			}
+		}
+	}
+
+	// 关闭超时未支付订单
+	private function closeOrders()
+	{
+		// 关闭超时未支付的有赞云订单(有赞云收款二维码超过30分钟自动关闭,关闭后无法再支付,所以我们限制15分钟内必须付款)
+		$paymentList = Payment::query()->with(['order', 'order.coupon'])->where('status', 0)->where('created_at', '<=', date("Y-m-d H:i:s", strtotime("-15 minutes")))->get();
+		if(!$paymentList->isEmpty()){
+			DB::beginTransaction();
+			try{
+				foreach($paymentList as $payment){
+					// 关闭支付单
+					Payment::query()->where('id', $payment->id)->update(['status' => -1]);
+
+					// 关闭订单
+					Order::query()->where('oid', $payment->oid)->update(['status' => -1]);
+
+					// 退回优惠券
+					if($payment->order->coupon_id){
+						Coupon::query()->where('id', $payment->order->coupon_id)->update(['status' => 0]);
+
+						Helpers::addCouponLog($payment->order->coupon_id, $payment->order->goods_id, $payment->oid, '订单超时未支付,自动退回');
+					}
+				}
+
+				DB::commit();
+			} catch(Exception $e){
+				Log::info('【异常】自动关闭超时未支付订单:'.$e);
+
+				DB::rollBack();
+			}
+		}
+	}
+
+	// 关闭超过72小时未处理的工单
+	private function closeTickets()
+	{
+		$ticketList = Ticket::query()->where('updated_at', '<=', date('Y-m-d H:i:s', strtotime("-72 hours")))->where('status', 1)->get();
+		foreach($ticketList as $ticket){
+			$ret = Ticket::query()->where('id', $ticket->id)->update(['status' => 2]);
+			if($ret){
+				ServerChan::send('工单关闭提醒', '工单:ID'.$ticket->id.'超过72小时未处理,系统已自动关闭');
+			}
+		}
+	}
+
+	// 检测节点是否离线
+	private function checkNodeStatus()
+	{
+		if(Helpers::systemConfig()['is_node_crash_warning']){
+			$nodeList = SsNode::query()->where('is_transit', 0)->where('status', 1)->get();
+			foreach($nodeList as $node){
+				// 10分钟内无节点负载信息且TCP检测认为不是离线则认为是后端炸了
+				$nodeTTL = SsNodeInfo::query()->where('node_id', $node->id)->where('log_time', '>=', strtotime("-10 minutes"))->orderBy('id', 'desc')->first();
+				if(!$nodeTTL){
+					ServerChan::send('节点异常警告', "节点**{$node->name}【{$node->ip}】**异常:**心跳异常,可能离线了**");
+				}
+			}
+		}
+	}
+
+	/**
+	 * 添加用户封禁日志
+	 *
+	 * @param int    $userId  用户ID
+	 * @param int    $minutes 封禁时长,单位分钟
+	 * @param string $desc    封禁理由
+	 */
+	private function addUserBanLog($userId, $minutes, $desc)
+	{
+		$log = new UserBanLog();
+		$log->user_id = $userId;
+		$log->minutes = $minutes;
+		$log->desc = $desc;
+		$log->save();
+	}
+
+	/**
+	 * 添加返利日志
+	 *
+	 * @param int $userId    用户ID
+	 * @param int $refUserId 返利用户ID
+	 * @param int $oid       订单ID
+	 * @param int $amount    发生金额
+	 * @param int $refAmount 返利金额
+	 *
+	 * @return int
+	 */
+	public function addReferralLog($userId, $refUserId, $oid, $amount, $refAmount)
+	{
+		$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();
+	}
+
+	/**
+	 * 记录余额操作日志
+	 *
+	 * @param int    $userId 用户ID
+	 * @param string $oid    订单ID
+	 * @param int    $before 记录前余额
+	 * @param int    $after  记录后余额
+	 * @param int    $amount 发生金额
+	 * @param string $desc   描述
+	 *
+	 * @return int
+	 */
+	public function addUserBalanceLog($userId, $oid, $before, $after, $amount, $desc = '')
+	{
+		$log = new UserBalanceLog();
+		$log->user_id = $userId;
+		$log->order_id = $oid;
+		$log->before = $before;
+		$log->after = $after;
+		$log->amount = $amount;
+		$log->desc = $desc;
+		$log->created_at = date('Y-m-d H:i:s');
+
+		return $log->save();
+	}
 }

+ 41 - 41
app/Console/Commands/AutoReportNode.php

@@ -11,45 +11,45 @@ use Log;
 
 class AutoReportNode extends Command
 {
-    protected $signature = 'autoReportNode';
-    protected $description = '自动报告节点昨日使用情况';
-    protected static $systemConfig;
-
-    public function __construct()
-    {
-        parent::__construct();
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
-
-        if (self::$systemConfig['node_daily_report']) {
-            $nodeList = SsNode::query()->where('status', 1)->get();
-            if (!$nodeList->isEmpty()) {
-                $msg = "|节点|上行流量|下行流量|合计|\r\n| :------ | :------ | :------ |\r\n";
-                foreach ($nodeList as $node) {
-                    $log = SsNodeTrafficDaily::query()
-                        ->where('node_id', $node->id)
-                        ->where('created_at', '>=', date('Y-m-d 00:00:00', strtotime("-1 day")))
-                        ->where('created_at', '<=', date('Y-m-d 23:59:59', strtotime("-1 day")))
-                        ->first();
-
-                    if ($log) {
-                        $msg .= '|' . $node->name . '|' . flowAutoShow($log->u) . '|' . flowAutoShow($log->d) . '|' . $log->traffic . "\r\n";
-                    } else {
-                        $msg .= '|' . $node->name . '|' . flowAutoShow(0) . '|' . flowAutoShow(0) . "|0B\r\n";
-                    }
-                }
-
-                ServerChan::send('节点日报', $msg);
-            }
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
+	protected $signature = 'autoReportNode';
+	protected $description = '自动报告节点昨日使用情况';
+	protected static $systemConfig;
+
+	public function __construct()
+	{
+		parent::__construct();
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
+
+		if(self::$systemConfig['node_daily_report']){
+			$nodeList = SsNode::query()->where('status', 1)->get();
+			if(!$nodeList->isEmpty()){
+				$msg = "|节点|上行流量|下行流量|合计|\r\n| :------ | :------ | :------ |\r\n";
+				foreach($nodeList as $node){
+					$log = SsNodeTrafficDaily::query()
+						->where('node_id', $node->id)
+						->where('created_at', '>=', date('Y-m-d 00:00:00', strtotime("-1 day")))
+						->where('created_at', '<=', date('Y-m-d 23:59:59', strtotime("-1 day")))
+						->first();
+
+					if($log){
+						$msg .= '|'.$node->name.'|'.flowAutoShow($log->u).'|'.flowAutoShow($log->d).'|'.$log->traffic."\r\n";
+					}else{
+						$msg .= '|'.$node->name.'|'.flowAutoShow(0).'|'.flowAutoShow(0)."|0B\r\n";
+					}
+				}
+
+				ServerChan::send('节点日报', $msg);
+			}
+		}
+
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
+
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
 }

+ 59 - 59
app/Console/Commands/AutoResetUserTraffic.php

@@ -3,78 +3,78 @@
 namespace App\Console\Commands;
 
 use App\Components\Helpers;
-use Illuminate\Console\Command;
 use App\Http\Models\Order;
 use App\Http\Models\User;
+use Illuminate\Console\Command;
 use Log;
 
 class AutoResetUserTraffic extends Command
 {
-    protected $signature = 'autoResetUserTraffic';
-    protected $description = '自动重置用户可用流量';
-    protected static $systemConfig;
+	protected $signature = 'autoResetUserTraffic';
+	protected $description = '自动重置用户可用流量';
+	protected static $systemConfig;
 
-    public function __construct()
-    {
-        parent::__construct();
-        self::$systemConfig = Helpers::systemConfig();
-    }
+	public function __construct()
+	{
+		parent::__construct();
+		self::$systemConfig = Helpers::systemConfig();
+	}
 
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
 
-        // 重置用户流量
-        if (self::$systemConfig['reset_traffic']) {
-            $this->resetUserTraffic();
-        }
+		// 重置用户流量
+		if(self::$systemConfig['reset_traffic']){
+			$this->resetUserTraffic();
+		}
 
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
 
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
 
-    // 重置用户流量
-    private function resetUserTraffic()
-    {
-        $userList = User::query()->where('status', '>=', 0)->where('expire_time', '>=', date('Y-m-d'))->get();
-        if (!$userList->isEmpty()) {
-            foreach ($userList as $user) {
-                if (!$user->traffic_reset_day) {
-                    continue;
-                }
+	// 重置用户流量
+	private function resetUserTraffic()
+	{
+		$userList = User::query()->where('status', '>=', 0)->where('expire_time', '>=', date('Y-m-d'))->get();
+		if(!$userList->isEmpty()){
+			foreach($userList as $user){
+				if(!$user->traffic_reset_day){
+					continue;
+				}
 
-                // 取出用户购买的有效套餐
-                $order = Order::query()
-                    ->with(['user', 'goods'])
-                    ->whereHas('goods', function ($q) {
-                        $q->where('type', 2);
-                    })
-                    ->where('user_id', $user->id)
-                    ->where('is_expire', 0)
-                    ->orderBy('oid', 'desc')
-                    ->first();
+				// 取出用户购买的有效套餐
+				$order = Order::query()
+					->with(['user', 'goods'])
+					->whereHas('goods', function($q){
+						$q->where('type', 2);
+					})
+					->where('user_id', $user->id)
+					->where('is_expire', 0)
+					->orderBy('oid', 'desc')
+					->first();
 
-                if (!$order) {
-                    continue;
-                }
+				if(!$order){
+					continue;
+				}
 
-                $month = date('m');
-                $today = date('d');
-                $last_day= date('t');
-                $resetDay = $order->user->traffic_reset_day;
-                if ($resetDay == $today || ($today == $last_day && $resetDay > $last_day)) {
-                    // 跳过本月,防止异常重置
-                    if ($month == date('m', strtotime($order->expire_at))) {
-                        continue;
-                    } elseif ($month == date('m', strtotime($order->created_at))) {
-                        continue;
-                    }
-                    // 重置流量
-                    User::query()->where('id', $user->id)->update(['u' => 0, 'd' => 0,'transfer_enable' => $order->goods->traffic * 1048576]);
-                }
-            }
-        }
-    }
+				$month = date('m');
+				$today = date('d');
+				$last_day = date('t');
+				$resetDay = $order->user->traffic_reset_day;
+				if($resetDay == $today || ($today == $last_day && $resetDay > $last_day)){
+					// 跳过本月,防止异常重置
+					if($month == date('m', strtotime($order->expire_at))){
+						continue;
+					}elseif($month == date('m', strtotime($order->created_at))){
+						continue;
+					}
+					// 重置流量
+					User::query()->where('id', $user->id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => $order->goods->traffic*1048576]);
+				}
+			}
+		}
+	}
 }

+ 46 - 46
app/Console/Commands/AutoStatisticsNodeDailyTraffic.php

@@ -2,57 +2,57 @@
 
 namespace App\Console\Commands;
 
-use Illuminate\Console\Command;
 use App\Http\Models\SsNode;
 use App\Http\Models\SsNodeTrafficDaily;
 use App\Http\Models\UserTrafficLog;
+use Illuminate\Console\Command;
 use Log;
 
 class AutoStatisticsNodeDailyTraffic extends Command
 {
-    protected $signature = 'autoStatisticsNodeDailyTraffic';
-    protected $description = '自动统计节点每日流量';
-
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
-
-        $nodeList = SsNode::query()->where('status', 1)->orderBy('id', 'asc')->get();
-        foreach ($nodeList as $node) {
-            $this->statisticsByNode($node->id);
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
-
-    private function statisticsByNode($node_id)
-    {
-        $start_time = strtotime(date('Y-m-d 00:00:00', strtotime("-1 day")));
-        $end_time = strtotime(date('Y-m-d 23:59:59', strtotime("-1 day")));
-
-        $query = UserTrafficLog::query()->where('node_id', $node_id)->whereBetween('log_time', [$start_time, $end_time]);
-
-        $u = $query->sum('u');
-        $d = $query->sum('d');
-        $total = $u + $d;
-        $traffic = flowAutoShow($total);
-
-        if ($total) { // 有数据才记录
-            $obj = new SsNodeTrafficDaily();
-            $obj->node_id = $node_id;
-            $obj->u = $u;
-            $obj->d = $d;
-            $obj->total = $total;
-            $obj->traffic = $traffic;
-            $obj->save();
-        }
-    }
+	protected $signature = 'autoStatisticsNodeDailyTraffic';
+	protected $description = '自动统计节点每日流量';
+
+	public function __construct()
+	{
+		parent::__construct();
+	}
+
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
+
+		$nodeList = SsNode::query()->where('status', 1)->orderBy('id', 'asc')->get();
+		foreach($nodeList as $node){
+			$this->statisticsByNode($node->id);
+		}
+
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
+
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
+
+	private function statisticsByNode($node_id)
+	{
+		$start_time = strtotime(date('Y-m-d 00:00:00', strtotime("-1 day")));
+		$end_time = strtotime(date('Y-m-d 23:59:59', strtotime("-1 day")));
+
+		$query = UserTrafficLog::query()->where('node_id', $node_id)->whereBetween('log_time', [$start_time, $end_time]);
+
+		$u = $query->sum('u');
+		$d = $query->sum('d');
+		$total = $u+$d;
+		$traffic = flowAutoShow($total);
+
+		if($total){ // 有数据才记录
+			$obj = new SsNodeTrafficDaily();
+			$obj->node_id = $node_id;
+			$obj->u = $u;
+			$obj->d = $d;
+			$obj->total = $total;
+			$obj->traffic = $traffic;
+			$obj->save();
+		}
+	}
 }

+ 46 - 46
app/Console/Commands/AutoStatisticsNodeHourlyTraffic.php

@@ -2,57 +2,57 @@
 
 namespace App\Console\Commands;
 
-use Illuminate\Console\Command;
 use App\Http\Models\SsNode;
 use App\Http\Models\SsNodeTrafficHourly;
 use App\Http\Models\UserTrafficLog;
+use Illuminate\Console\Command;
 use Log;
 
 class AutoStatisticsNodeHourlyTraffic extends Command
 {
-    protected $signature = 'autoStatisticsNodeHourlyTraffic';
-    protected $description = '自动统计节点每小时流量';
-
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
-
-        $nodeList = SsNode::query()->where('status', 1)->orderBy('id', 'asc')->get();
-        foreach ($nodeList as $node) {
-            $this->statisticsByNode($node->id);
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
-
-    private function statisticsByNode($node_id)
-    {
-        $start_time = strtotime(date('Y-m-d H:i:s', strtotime("-1 hour")));
-        $end_time = time();
-
-        $query = UserTrafficLog::query()->where('node_id', $node_id)->whereBetween('log_time', [$start_time, $end_time]);
-
-        $u = $query->sum('u');
-        $d = $query->sum('d');
-        $total = $u + $d;
-        $traffic = flowAutoShow($total);
-
-        if ($total) { // 有数据才记录
-            $obj = new SsNodeTrafficHourly();
-            $obj->node_id = $node_id;
-            $obj->u = $u;
-            $obj->d = $d;
-            $obj->total = $total;
-            $obj->traffic = $traffic;
-            $obj->save();
-        }
-    }
+	protected $signature = 'autoStatisticsNodeHourlyTraffic';
+	protected $description = '自动统计节点每小时流量';
+
+	public function __construct()
+	{
+		parent::__construct();
+	}
+
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
+
+		$nodeList = SsNode::query()->where('status', 1)->orderBy('id', 'asc')->get();
+		foreach($nodeList as $node){
+			$this->statisticsByNode($node->id);
+		}
+
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
+
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
+
+	private function statisticsByNode($node_id)
+	{
+		$start_time = strtotime(date('Y-m-d H:i:s', strtotime("-1 hour")));
+		$end_time = time();
+
+		$query = UserTrafficLog::query()->where('node_id', $node_id)->whereBetween('log_time', [$start_time, $end_time]);
+
+		$u = $query->sum('u');
+		$d = $query->sum('d');
+		$total = $u+$d;
+		$traffic = flowAutoShow($total);
+
+		if($total){ // 有数据才记录
+			$obj = new SsNodeTrafficHourly();
+			$obj->node_id = $node_id;
+			$obj->u = $u;
+			$obj->d = $d;
+			$obj->total = $total;
+			$obj->traffic = $traffic;
+			$obj->save();
+		}
+	}
 }

+ 47 - 47
app/Console/Commands/AutoStatisticsUserDailyTraffic.php

@@ -2,70 +2,70 @@
 
 namespace App\Console\Commands;
 
-use Illuminate\Console\Command;
 use App\Http\Models\SsNode;
 use App\Http\Models\User;
 use App\Http\Models\UserTrafficDaily;
 use App\Http\Models\UserTrafficLog;
+use Illuminate\Console\Command;
 use Log;
 
 class AutoStatisticsUserDailyTraffic extends Command
 {
-    protected $signature = 'autoStatisticsUserDailyTraffic';
-    protected $description = '自动统计用户每日流量';
+	protected $signature = 'autoStatisticsUserDailyTraffic';
+	protected $description = '自动统计用户每日流量';
 
-    public function __construct()
-    {
-        parent::__construct();
-    }
+	public function __construct()
+	{
+		parent::__construct();
+	}
 
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
 
-        $userList = User::query()->where('status', '>=', 0)->where('enable', 1)->get();
-        foreach ($userList as $user) {
-            // 统计一次所有节点的总和
-            $this->statisticsByNode($user->id);
+		$userList = User::query()->where('status', '>=', 0)->where('enable', 1)->get();
+		foreach($userList as $user){
+			// 统计一次所有节点的总和
+			$this->statisticsByNode($user->id);
 
-            // 统计每个节点产生的流量
-            $nodeList = SsNode::query()->where('status', 1)->orderBy('id', 'asc')->get();
-            foreach ($nodeList as $node) {
-                $this->statisticsByNode($user->id, $node->id);
-            }
-        }
+			// 统计每个节点产生的流量
+			$nodeList = SsNode::query()->where('status', 1)->orderBy('id', 'asc')->get();
+			foreach($nodeList as $node){
+				$this->statisticsByNode($user->id, $node->id);
+			}
+		}
 
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
 
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
 
-    private function statisticsByNode($user_id, $node_id = 0)
-    {
-        $start_time = strtotime(date('Y-m-d 00:00:00', strtotime("-1 day")));
-        $end_time = strtotime(date('Y-m-d 23:59:59', strtotime("-1 day")));
+	private function statisticsByNode($user_id, $node_id = 0)
+	{
+		$start_time = strtotime(date('Y-m-d 00:00:00', strtotime("-1 day")));
+		$end_time = strtotime(date('Y-m-d 23:59:59', strtotime("-1 day")));
 
-        $query = UserTrafficLog::query()->where('user_id', $user_id)->whereBetween('log_time', [$start_time, $end_time]);
+		$query = UserTrafficLog::query()->where('user_id', $user_id)->whereBetween('log_time', [$start_time, $end_time]);
 
-        if ($node_id) {
-            $query->where('node_id', $node_id);
-        }
+		if($node_id){
+			$query->where('node_id', $node_id);
+		}
 
-        $u = $query->sum('u');
-        $d = $query->sum('d');
-        $total = $u + $d;
-        $traffic = flowAutoShow($total);
+		$u = $query->sum('u');
+		$d = $query->sum('d');
+		$total = $u+$d;
+		$traffic = flowAutoShow($total);
 
-        if ($total) { // 有数据才记录
-            $obj = new UserTrafficDaily();
-            $obj->user_id = $user_id;
-            $obj->node_id = $node_id;
-            $obj->u = $u;
-            $obj->d = $d;
-            $obj->total = $total;
-            $obj->traffic = $traffic;
-            $obj->save();
-        }
-    }
+		if($total){ // 有数据才记录
+			$obj = new UserTrafficDaily();
+			$obj->user_id = $user_id;
+			$obj->node_id = $node_id;
+			$obj->u = $u;
+			$obj->d = $d;
+			$obj->total = $total;
+			$obj->traffic = $traffic;
+			$obj->save();
+		}
+	}
 }

+ 48 - 48
app/Console/Commands/AutoStatisticsUserHourlyTraffic.php

@@ -2,70 +2,70 @@
 
 namespace App\Console\Commands;
 
-use Illuminate\Console\Command;
 use App\Http\Models\SsNode;
 use App\Http\Models\User;
-use App\Http\Models\UserTrafficLog;
 use App\Http\Models\UserTrafficHourly;
+use App\Http\Models\UserTrafficLog;
+use Illuminate\Console\Command;
 use Log;
 
 class AutoStatisticsUserHourlyTraffic extends Command
 {
-    protected $signature = 'autoStatisticsUserHourlyTraffic';
-    protected $description = '自动统计用户每小时流量';
+	protected $signature = 'autoStatisticsUserHourlyTraffic';
+	protected $description = '自动统计用户每小时流量';
 
-    public function __construct()
-    {
-        parent::__construct();
-    }
+	public function __construct()
+	{
+		parent::__construct();
+	}
 
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
 
-        $userList = User::query()->where('status', '>=', 0)->where('enable', 1)->get();
-        foreach ($userList as $user) {
-            // 统计一次所有节点的总和
-            $this->statisticsByNode($user->id);
+		$userList = User::query()->where('status', '>=', 0)->where('enable', 1)->get();
+		foreach($userList as $user){
+			// 统计一次所有节点的总和
+			$this->statisticsByNode($user->id);
 
-            // 统计每个节点产生的流量
-            $nodeList = SsNode::query()->where('status', 1)->orderBy('id', 'asc')->get();
-            foreach ($nodeList as $node) {
-                $this->statisticsByNode($user->id, $node->id);
-            }
-        }
+			// 统计每个节点产生的流量
+			$nodeList = SsNode::query()->where('status', 1)->orderBy('id', 'asc')->get();
+			foreach($nodeList as $node){
+				$this->statisticsByNode($user->id, $node->id);
+			}
+		}
 
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
 
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
 
-    private function statisticsByNode($user_id, $node_id = 0)
-    {
-        $start_time = strtotime(date('Y-m-d H:i:s', strtotime("-1 hour")));
-        $end_time = time();
+	private function statisticsByNode($user_id, $node_id = 0)
+	{
+		$start_time = strtotime(date('Y-m-d H:i:s', strtotime("-1 hour")));
+		$end_time = time();
 
-        $query = UserTrafficLog::query()->where('user_id', $user_id)->whereBetween('log_time', [$start_time, $end_time]);
+		$query = UserTrafficLog::query()->where('user_id', $user_id)->whereBetween('log_time', [$start_time, $end_time]);
 
-        if ($node_id) {
-            $query->where('node_id', $node_id);
-        }
+		if($node_id){
+			$query->where('node_id', $node_id);
+		}
 
-        $u = $query->sum('u');
-        $d = $query->sum('d');
-        $total = $u + $d;
-        $traffic = flowAutoShow($total);
+		$u = $query->sum('u');
+		$d = $query->sum('d');
+		$total = $u+$d;
+		$traffic = flowAutoShow($total);
 
-        if ($total) { // 有数据才记录
-            $obj = new UserTrafficHourly();
-            $obj->user_id = $user_id;
-            $obj->node_id = $node_id;
-            $obj->u = $u;
-            $obj->d = $d;
-            $obj->total = $total;
-            $obj->traffic = $traffic;
-            $obj->save();
-        }
-    }
+		if($total){ // 有数据才记录
+			$obj = new UserTrafficHourly();
+			$obj->user_id = $user_id;
+			$obj->node_id = $node_id;
+			$obj->u = $u;
+			$obj->d = $d;
+			$obj->total = $total;
+			$obj->traffic = $traffic;
+			$obj->save();
+		}
+	}
 }

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

@@ -3,65 +3,65 @@
 namespace App\Console\Commands;
 
 use App\Components\Helpers;
-use Illuminate\Console\Command;
 use App\Http\Models\User;
 use App\Mail\userExpireWarning;
 use App\Mail\userExpireWarningToday;
-use Mail;
+use Illuminate\Console\Command;
 use Log;
+use Mail;
 
 class UserExpireAutoWarning extends Command
 {
-    protected $signature = 'userExpireAutoWarning';
-    protected $description = '用户临近到期自动发邮件提醒';
-    protected static $systemConfig;
+	protected $signature = 'userExpireAutoWarning';
+	protected $description = '用户临近到期自动发邮件提醒';
+	protected static $systemConfig;
 
-    public function __construct()
-    {
-        parent::__construct();
-        self::$systemConfig = Helpers::systemConfig();
-    }
+	public function __construct()
+	{
+		parent::__construct();
+		self::$systemConfig = Helpers::systemConfig();
+	}
 
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
 
-        // 用户临近到期自动发邮件提醒
-        if (self::$systemConfig['expire_warning']) {
-            $this->userExpireWarning();
-        }
+		// 用户临近到期自动发邮件提醒
+		if(self::$systemConfig['expire_warning']){
+			$this->userExpireWarning();
+		}
 
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
 
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
 
-    private function userExpireWarning()
-    {
-        // 只取SSR没被禁用的用户,其他不用管
-        $userList = User::query()->where('enable', 1)->get();
-        foreach ($userList as $user) {
-            // 用户名不是邮箱的跳过
-            if (false === filter_var($user->username, FILTER_VALIDATE_EMAIL)) {
-                continue;
-            }
+	private function userExpireWarning()
+	{
+		// 只取SSR没被禁用的用户,其他不用管
+		$userList = User::query()->where('enable', 1)->get();
+		foreach($userList as $user){
+			// 用户名不是邮箱的跳过
+			if(FALSE === filter_var($user->username, FILTER_VALIDATE_EMAIL)){
+				continue;
+			}
 
-            // 计算剩余可用时间
-            $lastCanUseDays = ceil(round(strtotime($user->expire_time) - strtotime(date('Y-m-d H:i:s'))) / 3600 / 24);
-            if ($lastCanUseDays == 0) {
-                $title = '账号过期提醒';
-                $content = '您的账号将于今天晚上【24:00】过期。';
+			// 计算剩余可用时间
+			$lastCanUseDays = ceil(round(strtotime($user->expire_time)-strtotime(date('Y-m-d H:i:s')))/3600/24);
+			if($lastCanUseDays == 0){
+				$title = '账号过期提醒';
+				$content = '您的账号将于今天晚上【24:00】过期。';
 
-                $logId = Helpers::addEmailLog($user->username, $title, $content);
-                Mail::to($user->username)->send(new userExpireWarningToday($logId));
-            } elseif ($lastCanUseDays > 0 && $lastCanUseDays <= self::$systemConfig['expire_days']) {
-                $title = '账号过期提醒';
-                $content = '您的账号还剩' . $lastCanUseDays . '天即将过期。';
+				$logId = Helpers::addEmailLog($user->username, $title, $content);
+				Mail::to($user->username)->send(new userExpireWarningToday($logId));
+			}elseif($lastCanUseDays > 0 && $lastCanUseDays <= self::$systemConfig['expire_days']){
+				$title = '账号过期提醒';
+				$content = '您的账号还剩'.$lastCanUseDays.'天即将过期。';
 
-                $logId = Helpers::addEmailLog($user->username, $title, $content);
-                Mail::to($user->username)->send(new userExpireWarning($logId, $lastCanUseDays));
-            }
-        }
-    }
+				$logId = Helpers::addEmailLog($user->username, $title, $content);
+				Mail::to($user->username)->send(new userExpireWarning($logId, $lastCanUseDays));
+			}
+		}
+	}
 }

+ 46 - 46
app/Console/Commands/UserTrafficAbnormalAutoWarning.php

@@ -4,56 +4,56 @@ namespace App\Console\Commands;
 
 use App\Components\Helpers;
 use App\Components\ServerChan;
-use Illuminate\Console\Command;
 use App\Http\Models\User;
 use App\Http\Models\UserTrafficHourly;
+use Illuminate\Console\Command;
 use Log;
 
 class UserTrafficAbnormalAutoWarning extends Command
 {
-    protected $signature = 'userTrafficAbnormalAutoWarning';
-    protected $description = '用户流量异常警告';
-    protected static $systemConfig;
-
-    public function __construct()
-    {
-        parent::__construct();
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
-
-        // 用户流量异常警告
-        $this->userTrafficAbnormalWarning();
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
-
-    // 用户流量异常警告
-    private function userTrafficAbnormalWarning()
-    {
-        // 1小时内流量异常用户(多往前取5分钟,防止数据统计任务执行时间过长导致没有数据)
-        $userTotalTrafficList = UserTrafficHourly::query()->where('node_id', 0)->where('total', '>', 104857600)->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))->groupBy('user_id')->selectRaw("user_id, sum(total) as totalTraffic")->get(); // 只统计100M以上的记录,加快查询速度
-        if (!$userTotalTrafficList->isEmpty()) {
-            $title = "流量异常用户提醒";
-
-            foreach ($userTotalTrafficList as $vo) {
-                $user = User::query()->where('id', $vo->user_id)->first();
-
-                // 通过ServerChan发微信消息提醒管理员
-                if ($vo->totalTraffic > (self::$systemConfig['traffic_ban_value'] * 1073741824)) {
-                    $traffic = UserTrafficHourly::query()->where('node_id', 0)->where('user_id', $vo->user_id)->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))->selectRaw("user_id, sum(`u`) as totalU, sum(`d`) as totalD, sum(total) as totalTraffic")->first();
-
-                    $content = "用户**{$user->username}(ID:{$user->id})**,最近1小时**上行流量:" . flowAutoShow($traffic->totalU) . ",下行流量:" . flowAutoShow($traffic->totalD) . ",共计:" . flowAutoShow($traffic->totalTraffic) . "**。";
-
-                    ServerChan::send($title, $content);
-                }
-            }
-        }
-    }
+	protected $signature = 'userTrafficAbnormalAutoWarning';
+	protected $description = '用户流量异常警告';
+	protected static $systemConfig;
+
+	public function __construct()
+	{
+		parent::__construct();
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
+
+		// 用户流量异常警告
+		$this->userTrafficAbnormalWarning();
+
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
+
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
+
+	// 用户流量异常警告
+	private function userTrafficAbnormalWarning()
+	{
+		// 1小时内流量异常用户(多往前取5分钟,防止数据统计任务执行时间过长导致没有数据)
+		$userTotalTrafficList = UserTrafficHourly::query()->where('node_id', 0)->where('total', '>', 104857600)->where('created_at', '>=', date('Y-m-d H:i:s', time()-3900))->groupBy('user_id')->selectRaw("user_id, sum(total) as totalTraffic")->get(); // 只统计100M以上的记录,加快查询速度
+		if(!$userTotalTrafficList->isEmpty()){
+			$title = "流量异常用户提醒";
+
+			foreach($userTotalTrafficList as $vo){
+				$user = User::query()->where('id', $vo->user_id)->first();
+
+				// 通过ServerChan发微信消息提醒管理员
+				if($vo->totalTraffic > (self::$systemConfig['traffic_ban_value']*1073741824)){
+					$traffic = UserTrafficHourly::query()->where('node_id', 0)->where('user_id', $vo->user_id)->where('created_at', '>=', date('Y-m-d H:i:s', time()-3900))->selectRaw("user_id, sum(`u`) as totalU, sum(`d`) as totalD, sum(total) as totalTraffic")->first();
+
+					$content = "用户**{$user->username}(ID:{$user->id})**,最近1小时**上行流量:".flowAutoShow($traffic->totalU).",下行流量:".flowAutoShow($traffic->totalD).",共计:".flowAutoShow($traffic->totalTraffic)."**。";
+
+					ServerChan::send($title, $content);
+				}
+			}
+		}
+	}
 }

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

@@ -3,57 +3,57 @@
 namespace App\Console\Commands;
 
 use App\Components\Helpers;
-use Illuminate\Console\Command;
 use App\Http\Models\User;
 use App\Mail\userTrafficWarning;
-use Mail;
+use Illuminate\Console\Command;
 use Log;
+use Mail;
 
 class UserTrafficAutoWarning extends Command
 {
-    protected $signature = 'userTrafficAutoWarning';
-    protected $description = '用户流量超过警告阈值自动发邮件提醒';
-    protected static $systemConfig;
-
-    public function __construct()
-    {
-        parent::__construct();
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    public function handle()
-    {
-        $jobStartTime = microtime(true);
-
-        // 用户流量超过警告阈值自动发邮件提醒
-        if (self::$systemConfig['traffic_warning']) {
-            $this->userTrafficWarning();
-        }
-
-        $jobEndTime = microtime(true);
-        $jobUsedTime = round(($jobEndTime - $jobStartTime), 4);
-
-        Log::info('执行定时任务【' . $this->description . '】,耗时' . $jobUsedTime . '秒');
-    }
-
-    // 用户流量超过警告阈值自动发邮件提醒
-    private function userTrafficWarning()
-    {
-        $userList = User::query()->where('status', '>=', 0)->where('enable', 1)->where('transfer_enable', '>', 0)->get();
-        foreach ($userList as $user) {
-            // 用户名不是邮箱的跳过
-            if (false === filter_var($user->username, FILTER_VALIDATE_EMAIL)) {
-                continue;
-            }
-
-            $usedPercent = round(($user->d + $user->u) / $user->transfer_enable, 2) * 100; // 已使用流量百分比
-            if ($usedPercent >= self::$systemConfig['traffic_warning_percent']) {
-                $title = '流量提醒';
-                $content = '流量已使用:' . $usedPercent . '%,请保持关注。';
-
-                $logId = Helpers::addEmailLog($user->username, $title, $content);
-                Mail::to($user->username)->send(new userTrafficWarning($logId, $usedPercent));
-            }
-        }
-    }
+	protected $signature = 'userTrafficAutoWarning';
+	protected $description = '用户流量超过警告阈值自动发邮件提醒';
+	protected static $systemConfig;
+
+	public function __construct()
+	{
+		parent::__construct();
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	public function handle()
+	{
+		$jobStartTime = microtime(TRUE);
+
+		// 用户流量超过警告阈值自动发邮件提醒
+		if(self::$systemConfig['traffic_warning']){
+			$this->userTrafficWarning();
+		}
+
+		$jobEndTime = microtime(TRUE);
+		$jobUsedTime = round(($jobEndTime-$jobStartTime), 4);
+
+		Log::info('执行定时任务【'.$this->description.'】,耗时'.$jobUsedTime.'秒');
+	}
+
+	// 用户流量超过警告阈值自动发邮件提醒
+	private function userTrafficWarning()
+	{
+		$userList = User::query()->where('status', '>=', 0)->where('enable', 1)->where('transfer_enable', '>', 0)->get();
+		foreach($userList as $user){
+			// 用户名不是邮箱的跳过
+			if(FALSE === filter_var($user->username, FILTER_VALIDATE_EMAIL)){
+				continue;
+			}
+
+			$usedPercent = round(($user->d+$user->u)/$user->transfer_enable, 2)*100; // 已使用流量百分比
+			if($usedPercent >= self::$systemConfig['traffic_warning_percent']){
+				$title = '流量提醒';
+				$content = '流量已使用:'.$usedPercent.'%,请保持关注。';
+
+				$logId = Helpers::addEmailLog($user->username, $title, $content);
+				Mail::to($user->username)->send(new userTrafficWarning($logId, $usedPercent));
+			}
+		}
+	}
 }

+ 43 - 42
app/Console/Commands/upgradeUserLabels.php

@@ -6,49 +6,50 @@ use App\Components\Helpers;
 use App\Http\Models\User;
 use App\Http\Models\UserLabel;
 use Illuminate\Console\Command;
+use Log;
 
 class upgradeUserLabels extends Command
 {
-    protected $signature = 'upgradeUserLabels';
-    protected $description = '初始化用户默认标签';
-    protected static $systemConfig;
-
-    public function __construct()
-    {
-        parent::__construct();
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    public function handle()
-    {
-        if (empty(self::$systemConfig['initial_labels_for_user'])) {
-            \Log::info('初始化用户默认标签失败:系统未设置默认标签');
-            exit();
-        }
-
-        $userList = User::query()->where('status', '>=', 0)->get();
-        foreach ($userList as $user) {
-            // 跳过已经有标签的用户
-            $count = UserLabel::query()->where('user_id', $user->id)->count();
-            if ($count) {
-                continue;
-            }
-
-            // 给用户生成默认标签
-            $this->makeUserDefaultLabels($user->id);
-        }
-    }
-
-    // 生成用户默认标签
-    private function makeUserDefaultLabels($userId)
-    {
-        $labels = explode(',', self::$systemConfig['initial_labels_for_user']);
-
-        foreach ($labels as $vo) {
-            $userLabel = new UserLabel();
-            $userLabel->user_id = $userId;
-            $userLabel->label_id = $vo;
-            $userLabel->save();
-        }
-    }
+	protected $signature = 'upgradeUserLabels';
+	protected $description = '初始化用户默认标签';
+	protected static $systemConfig;
+
+	public function __construct()
+	{
+		parent::__construct();
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	public function handle()
+	{
+		if(empty(self::$systemConfig['initial_labels_for_user'])){
+			Log::info('初始化用户默认标签失败:系统未设置默认标签');
+			exit();
+		}
+
+		$userList = User::query()->where('status', '>=', 0)->get();
+		foreach($userList as $user){
+			// 跳过已经有标签的用户
+			$count = UserLabel::query()->where('user_id', $user->id)->count();
+			if($count){
+				continue;
+			}
+
+			// 给用户生成默认标签
+			$this->makeUserDefaultLabels($user->id);
+		}
+	}
+
+	// 生成用户默认标签
+	private function makeUserDefaultLabels($userId)
+	{
+		$labels = explode(',', self::$systemConfig['initial_labels_for_user']);
+
+		foreach($labels as $vo){
+			$userLabel = new UserLabel();
+			$userLabel->user_id = $userId;
+			$userLabel->label_id = $vo;
+			$userLabel->save();
+		}
+	}
 }

+ 19 - 19
app/Console/Commands/upgradeUserPassword.php

@@ -3,31 +3,31 @@
 namespace App\Console\Commands;
 
 use App\Http\Models\User;
-use Illuminate\Console\Command;
 use Hash;
+use Illuminate\Console\Command;
 use Log;
 
 class upgradeUserPassword extends Command
 {
-    protected $signature = 'upgradeUserPassword';
-    protected $description = '用户密码升级(MD5->HASH)';
+	protected $signature = 'upgradeUserPassword';
+	protected $description = '用户密码升级(MD5->HASH)';
+
+	public function __construct()
+	{
+		parent::__construct();
+	}
 
-    public function __construct()
-    {
-        parent::__construct();
-    }
+	public function handle()
+	{
+		Log::info('----------------------------【升级用户登录密码】开始----------------------------');
 
-    public function handle()
-    {
-        Log::info('----------------------------【升级用户登录密码】开始----------------------------');
-        
-        // 将用户的登录密码由原有的md5升级为hash,统一升级为与用户名相同的密码
-        $userList = User::query()->get();
-        foreach ($userList as $user) {
-            User::query()->where('id', $user->id)->update(['password' => Hash::make($user->username)]);
-            Log::info('----------------------------升级用户[' . $user->username . ']的登录密码----------------------------');
-        }
+		// 将用户的登录密码由原有的md5升级为hash,统一升级为与用户名相同的密码
+		$userList = User::query()->get();
+		foreach($userList as $user){
+			User::query()->where('id', $user->id)->update(['password' => Hash::make($user->username)]);
+			Log::info('----------------------------升级用户['.$user->username.']的登录密码----------------------------');
+		}
 
-        Log::info('----------------------------【升级用户登录密码】结束----------------------------');
-    }
+		Log::info('----------------------------【升级用户登录密码】结束----------------------------');
+	}
 }

+ 25 - 25
app/Console/Commands/upgradeUserSpeedLimit.php

@@ -8,29 +8,29 @@ use Log;
 
 class upgradeUserSpeedLimit extends Command
 {
-    protected $signature = 'upgradeUserSpeedLimit';
-    protected $description = '升级用户限速字段,重置初始值';
-
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    public function handle()
-    {
-        Log::info('----------------------------【重置用户限速字段】开始----------------------------');
-
-        $userList = User::query()->get();
-        foreach ($userList as $user) {
-            $data = [
-                'speed_limit_per_con'  => 10737418240,
-                'speed_limit_per_user' => 10737418240
-            ];
-
-            User::query()->where('id', $user->id)->update($data);
-            Log::info('---用户[ID:' . $user->id . ' - ' . $user->username . ']的限速字段值被重置为10G---');
-        }
-
-        Log::info('----------------------------【重置用户限速字段】结束----------------------------');
-    }
+	protected $signature = 'upgradeUserSpeedLimit';
+	protected $description = '升级用户限速字段,重置初始值';
+
+	public function __construct()
+	{
+		parent::__construct();
+	}
+
+	public function handle()
+	{
+		Log::info('----------------------------【重置用户限速字段】开始----------------------------');
+
+		$userList = User::query()->get();
+		foreach($userList as $user){
+			$data = [
+				'speed_limit_per_con'  => 10737418240,
+				'speed_limit_per_user' => 10737418240
+			];
+
+			User::query()->where('id', $user->id)->update($data);
+			Log::info('---用户[ID:'.$user->id.' - '.$user->username.']的限速字段值被重置为10G---');
+		}
+
+		Log::info('----------------------------【重置用户限速字段】结束----------------------------');
+	}
 }

+ 29 - 29
app/Console/Commands/upgradeUserSubscribe.php

@@ -10,33 +10,33 @@ use Log;
 
 class upgradeUserSubscribe extends Command
 {
-    protected $signature = 'upgradeUserSubscribe';
-    protected $description = '生成用户的订阅码';
-
-    public function __construct()
-    {
-        parent::__construct();
-    }
-
-    public function handle()
-    {
-        Log::info('----------------------------【生成用户订阅码】开始----------------------------');
-
-        $userList = User::query()->get();
-        foreach ($userList as $user) {
-            // 如果未生成过订阅码则生成一个
-            $subscribe = UserSubscribe::query()->where('user_id', $user->id)->first();
-            if (!$subscribe) {
-                $subscribe = new UserSubscribe();
-                $subscribe->user_id = $user->id;
-                $subscribe->code = Helpers::makeSubscribeCode();
-                $subscribe->times = 0;
-                $subscribe->save();
-
-                Log::info('---生成用户[ID:' . $user->id . ' - ' . $user->username . ']的订阅码---');
-            }
-        }
-
-        Log::info('----------------------------【生成用户订阅码】结束----------------------------');
-    }
+	protected $signature = 'upgradeUserSubscribe';
+	protected $description = '生成用户的订阅码';
+
+	public function __construct()
+	{
+		parent::__construct();
+	}
+
+	public function handle()
+	{
+		Log::info('----------------------------【生成用户订阅码】开始----------------------------');
+
+		$userList = User::query()->get();
+		foreach($userList as $user){
+			// 如果未生成过订阅码则生成一个
+			$subscribe = UserSubscribe::query()->where('user_id', $user->id)->first();
+			if(!$subscribe){
+				$subscribe = new UserSubscribe();
+				$subscribe->user_id = $user->id;
+				$subscribe->code = Helpers::makeSubscribeCode();
+				$subscribe->times = 0;
+				$subscribe->save();
+
+				Log::info('---生成用户[ID:'.$user->id.' - '.$user->username.']的订阅码---');
+			}
+		}
+
+		Log::info('----------------------------【生成用户订阅码】结束----------------------------');
+	}
 }

+ 20 - 19
app/Console/Commands/upgradeUserVmessId.php

@@ -4,29 +4,30 @@ namespace App\Console\Commands;
 
 use App\Http\Models\User;
 use Illuminate\Console\Command;
+use Log;
 
 class upgradeUserVmessId extends Command
 {
-    protected $signature = 'upgradeUserVmessId';
-    protected $description = '重新生成用户的vmess_id字段';
+	protected $signature = 'upgradeUserVmessId';
+	protected $description = '重新生成用户的vmess_id字段';
 
-    public function __construct()
-    {
-        parent::__construct();
-    }
+	public function __construct()
+	{
+		parent::__construct();
+	}
 
-    public function handle()
-    {
-        $userList = User::query()->get();
-        foreach ($userList as $user) {
-            if (!isset($user->vmess_id)) {
-                \Log::error("USER表缺失vmess_id字段,请先维护数据库字典");
-                break;
-            }
+	public function handle()
+	{
+		$userList = User::query()->get();
+		foreach($userList as $user){
+			if(!isset($user->vmess_id)){
+				Log::error("USER表缺失vmess_id字段,请先维护数据库字典");
+				break;
+			}
 
-            if (!$user->vmess_id) {
-                User::query()->where('id', $user->id)->update(['vmess_id' => createGuid()]);
-            }
-        }
-    }
+			if(!$user->vmess_id){
+				User::query()->where('id', $user->id)->update(['vmess_id' => createGuid()]);
+			}
+		}
+	}
 }

+ 76 - 58
app/Console/Kernel.php

@@ -2,70 +2,88 @@
 
 namespace App\Console;
 
+use App\Console\Commands\AutoCheckNodeTCP;
+use App\Console\Commands\AutoClearLog;
+use App\Console\Commands\AutoDecGoodsTraffic;
+use App\Console\Commands\AutoJob;
+use App\Console\Commands\AutoReportNode;
+use App\Console\Commands\AutoResetUserTraffic;
+use App\Console\Commands\AutoStatisticsNodeDailyTraffic;
+use App\Console\Commands\AutoStatisticsNodeHourlyTraffic;
+use App\Console\Commands\AutoStatisticsUserDailyTraffic;
+use App\Console\Commands\AutoStatisticsUserHourlyTraffic;
+use App\Console\Commands\upgradeUserLabels;
+use App\Console\Commands\upgradeUserPassword;
+use App\Console\Commands\upgradeUserSpeedLimit;
+use App\Console\Commands\upgradeUserSubscribe;
+use App\Console\Commands\upgradeUserVmessId;
+use App\Console\Commands\UserExpireAutoWarning;
+use App\Console\Commands\UserTrafficAbnormalAutoWarning;
+use App\Console\Commands\UserTrafficAutoWarning;
 use Illuminate\Console\Scheduling\Schedule;
 use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
 
 class Kernel extends ConsoleKernel
 {
-    /**
-     * The Artisan commands provided by your application.
-     *
-     * @var array
-     */
-    protected $commands = [
-        \App\Console\Commands\AutoJob::class,
-        \App\Console\Commands\AutoClearLog::class,
-        \App\Console\Commands\AutoDecGoodsTraffic::class,
-        \App\Console\Commands\AutoResetUserTraffic::class,
-        \App\Console\Commands\AutoCheckNodeTCP::class,
-        \App\Console\Commands\AutoStatisticsNodeDailyTraffic::class,
-        \App\Console\Commands\AutoStatisticsNodeHourlyTraffic::class,
-        \App\Console\Commands\AutoStatisticsUserDailyTraffic::class,
-        \App\Console\Commands\AutoStatisticsUserHourlyTraffic::class,
-        \App\Console\Commands\UserTrafficAbnormalAutoWarning::class,
-        \App\Console\Commands\UserExpireAutoWarning::class,
-        \App\Console\Commands\UserTrafficAutoWarning::class,
-        \App\Console\Commands\upgradeUserLabels::class,
-        \App\Console\Commands\upgradeUserPassword::class,
-        \App\Console\Commands\upgradeUserSpeedLimit::class,
-        \App\Console\Commands\upgradeUserSubscribe::class,
-        \App\Console\Commands\upgradeUserVmessId::class,
-        \App\Console\Commands\AutoReportNode::class,
-    ];
+	/**
+	 * The Artisan commands provided by your application.
+	 *
+	 * @var array
+	 */
+	protected $commands = [
+		AutoJob::class,
+		AutoClearLog::class,
+		AutoDecGoodsTraffic::class,
+		AutoResetUserTraffic::class,
+		AutoCheckNodeTCP::class,
+		AutoStatisticsNodeDailyTraffic::class,
+		AutoStatisticsNodeHourlyTraffic::class,
+		AutoStatisticsUserDailyTraffic::class,
+		AutoStatisticsUserHourlyTraffic::class,
+		UserTrafficAbnormalAutoWarning::class,
+		UserExpireAutoWarning::class,
+		UserTrafficAutoWarning::class,
+		upgradeUserLabels::class,
+		upgradeUserPassword::class,
+		upgradeUserSpeedLimit::class,
+		upgradeUserSubscribe::class,
+		upgradeUserVmessId::class,
+		AutoReportNode::class,
+	];
 
-    /**
-     * Define the application's command schedule.
-     *
-     * @param  \Illuminate\Console\Scheduling\Schedule $schedule
-     *
-     * @return void
-     */
-    protected function schedule(Schedule $schedule)
-    {
-        $schedule->command('autoJob')->everyMinute();
-        $schedule->command('autoClearLog')->everyThirtyMinutes();
-        $schedule->command('autoDecGoodsTraffic')->everyTenMinutes();
-        $schedule->command('autoResetUserTraffic')->daily();
-        $schedule->command('autoCheckNodeTCP')->everyMinute();
-        $schedule->command('autoStatisticsNodeDailyTraffic')->dailyAt('23:55');
-        $schedule->command('autoStatisticsNodeHourlyTraffic')->hourly();
-        $schedule->command('autoStatisticsUserDailyTraffic')->dailyAt('23:50');
-        $schedule->command('autoStatisticsUserHourlyTraffic')->hourly();
-        $schedule->command('userTrafficAbnormalAutoWarning')->hourly();
-        $schedule->command('userExpireAutoWarning')->dailyAt('20:00');
-        $schedule->command('userTrafficAutoWarning')->dailyAt('10:30');
-        $schedule->command('autoReportNode')->dailyAt('09:00');
-    }
+	/**
+	 * Define the application's command schedule.
+	 *
+	 * @param Schedule $schedule
+	 *
+	 * @return void
+	 */
+	protected function schedule(Schedule $schedule)
+	{
+		$schedule->command('autoJob')->everyMinute();
+		$schedule->command('autoClearLog')->everyThirtyMinutes();
+		$schedule->command('autoDecGoodsTraffic')->everyTenMinutes();
+		$schedule->command('autoResetUserTraffic')->daily();
+		$schedule->command('autoCheckNodeTCP')->everyMinute();
+		$schedule->command('autoStatisticsNodeDailyTraffic')->dailyAt('23:55');
+		$schedule->command('autoStatisticsNodeHourlyTraffic')->hourly();
+		$schedule->command('autoStatisticsUserDailyTraffic')->dailyAt('23:50');
+		$schedule->command('autoStatisticsUserHourlyTraffic')->hourly();
+		$schedule->command('userTrafficAbnormalAutoWarning')->hourly();
+		$schedule->command('userExpireAutoWarning')->dailyAt('20:00');
+		$schedule->command('userTrafficAutoWarning')->dailyAt('10:30');
+		$schedule->command('autoReportNode')->dailyAt('09:00');
+	}
 
-    /**
-     * Register the commands for the application.
-     *
-     * @return void
-     */
-    protected function commands()
-    {
-        $this->load(__DIR__.'/Commands');
+	/**
+	 * Register the commands for the application.
+	 *
+	 * @return void
+	 */
+	protected function commands()
+	{
+		$this->load(__DIR__.'/Commands');
 
-        require base_path('routes/console.php');
-    }
+		require base_path('routes/console.php');
+	}
 }

+ 21 - 23
app/Events/Event.php

@@ -3,34 +3,32 @@
 namespace App\Events;
 
 use Illuminate\Broadcasting\Channel;
-use Illuminate\Queue\SerializesModels;
+use Illuminate\Broadcasting\InteractsWithSockets;
 use Illuminate\Broadcasting\PrivateChannel;
-use Illuminate\Broadcasting\PresenceChannel;
 use Illuminate\Foundation\Events\Dispatchable;
-use Illuminate\Broadcasting\InteractsWithSockets;
-use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
+use Illuminate\Queue\SerializesModels;
 
 class Event
 {
-    use Dispatchable, InteractsWithSockets, SerializesModels;
+	use Dispatchable, InteractsWithSockets, SerializesModels;
 
-    /**
-     * Create a new event instance.
-     *
-     * @return void
-     */
-    public function __construct()
-    {
-        //
-    }
+	/**
+	 * Create a new event instance.
+	 *
+	 * @return void
+	 */
+	public function __construct()
+	{
+		//
+	}
 
-    /**
-     * Get the channels the event should broadcast on.
-     *
-     * @return \Illuminate\Broadcasting\Channel|array
-     */
-    public function broadcastOn()
-    {
-        return new PrivateChannel('channel-name');
-    }
+	/**
+	 * Get the channels the event should broadcast on.
+	 *
+	 * @return Channel|array
+	 */
+	public function broadcastOn()
+	{
+		return new PrivateChannel('channel-name');
+	}
 }

+ 95 - 92
app/Exceptions/Handler.php

@@ -6,114 +6,117 @@ use ErrorException;
 use Exception;
 use Illuminate\Auth\AuthenticationException;
 use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
+use Illuminate\Http\Request;
+use Illuminate\Http\Response;
 use Illuminate\Session\TokenMismatchException;
+use Log;
 use ReflectionException;
 use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
 
 class Handler extends ExceptionHandler
 {
-    /**
-     * A list of the exception types that are not reported.
-     *
-     * @var array
-     */
-    protected $dontReport = [
-        //
-    ];
+	/**
+	 * A list of the exception types that are not reported.
+	 *
+	 * @var array
+	 */
+	protected $dontReport = [
+		//
+	];
 
-    /**
-     * A list of the inputs that are never flashed for validation exceptions.
-     *
-     * @var array
-     */
-    protected $dontFlash = [
-        'password',
-        'password_confirmation',
-    ];
+	/**
+	 * A list of the inputs that are never flashed for validation exceptions.
+	 *
+	 * @var array
+	 */
+	protected $dontFlash = [
+		'password',
+		'password_confirmation',
+	];
 
-    /**
-     * Report or log an exception.
-     *
-     * @param Exception $exception
-     *
-     * @return mixed|void
-     * @throws Exception
-     */
-    public function report(Exception $exception)
-    {
-        // 记录异常来源
-        \Log::info('异常来源:' . get_class($exception));
+	/**
+	 * Report or log an exception.
+	 *
+	 * @param Exception $exception
+	 *
+	 * @return mixed|void
+	 * @throws Exception
+	 */
+	public function report(Exception $exception)
+	{
+		// 记录异常来源
+		Log::info('异常来源:'.get_class($exception));
 
-        // 调试模式下记录错误详情
-        if (config('app.debug')) {
-            \Log::info($exception);
-        }
+		// 调试模式下记录错误详情
+		if(config('app.debug')){
+			Log::info($exception);
+		}
 
-        parent::report($exception);
-    }
+		parent::report($exception);
+	}
 
-    /**
-     * Render an exception into an HTTP response.
-     *
-     * @param  \Illuminate\Http\Request $request
-     * @param  \Exception               $exception
-     *
-     * @return \Illuminate\Http\Response
-     */
-    public function render($request, Exception $exception)
-    {
-        // 调试模式下直接返回错误信息
-        if (config('app.debug')) {
-            return parent::render($request, $exception);
-        }
+	/**
+	 * Render an exception into an HTTP response.
+	 *
+	 * @param Request $request
+	 * @param Exception                $exception
+	 *
+	 * @return Response
+	 */
+	public function render($request, Exception $exception)
+	{
+		// 调试模式下直接返回错误信息
+		if(config('app.debug')){
+			return parent::render($request, $exception);
+		}
 
-        // 捕获访问异常
-        if ($exception instanceof NotFoundHttpException) {
-            \Log::info("异常请求:" . $request->fullUrl() . ",IP:" . getClientIp());
+		// 捕获访问异常
+		if($exception instanceof NotFoundHttpException){
+			Log::info("异常请求:".$request->fullUrl().",IP:".getClientIp());
 
-            if ($request->ajax()) {
-                return response()->json(['status' => 'fail', 'data' => '', 'message' => 'Page Not Found']);
-            } else {
-                return response()->view('auth.error', ['message' => trans('error.MissingPage')]);
-            }
-        }
+			if($request->ajax()){
+				return response()->json(['status' => 'fail', 'data' => '', 'message' => 'Page Not Found']);
+			}else{
+				return response()->view('auth.error', ['message' => trans('error.MissingPage')]);
+			}
+		}
 
-        // 捕获身份校验异常
-        if ($exception instanceof AuthenticationException) {
-            if ($request->ajax()) {
-                return response()->json(['status' => 'fail', 'data' => '', 'message' => 'Unauthorized']);
-            } else {
-                return response()->view('auth.error', ['message' => trans('error.Unauthorized')]);
-            }
-        }
+		// 捕获身份校验异常
+		if($exception instanceof AuthenticationException){
+			if($request->ajax()){
+				return response()->json(['status' => 'fail', 'data' => '', 'message' => 'Unauthorized']);
+			}else{
+				return response()->view('auth.error', ['message' => trans('error.Unauthorized')]);
+			}
+		}
 
-        // 捕获CSRF异常
-        if ($exception instanceof TokenMismatchException) {
-            if ($request->ajax()) {
-                return response()->json(['status' => 'fail', 'data' => '', 'message' => 'System Error, Please Refresh Page, Try One More Time']);
-            } else {
-                return response()->view('auth.error', ['message' => trans('error.RefreshPage')]);
-            }
-        }
+		// 捕获CSRF异常
+		if($exception instanceof TokenMismatchException){
+			if($request->ajax()){
+				return response()->json(['status' => 'fail', 'data' => '', 'message' => 'System Error, Please Refresh Page, Try One More Time']);
+			}else{
+				return response()->view('auth.error', ['message' => trans('error.RefreshPage')]);
+			}
+		}
 
-        // 捕获反射异常
-        if ($exception instanceof ReflectionException) {
-            if ($request->ajax()) {
-                return response()->json(['status' => 'fail', 'data' => '', 'message' => 'System Error']);
-            } else {
-                return response()->view('auth.error', ['message' => trans('error.SystemError')]);
-            }
-        }
+		// 捕获反射异常
+		if($exception instanceof ReflectionException){
+			if($request->ajax()){
+				return response()->json(['status' => 'fail', 'data' => '', 'message' => 'System Error']);
+			}else{
+				return response()->view('auth.error', ['message' => trans('error.SystemError')]);
+			}
+		}
 
-        // 捕获系统错误异常
-        if ($exception instanceof ErrorException) {
-            if ($request->ajax()) {
-                return response()->json(['status' => 'fail', 'data' => '', 'message' => 'System Error']);
-            } else {
-                return response()->view('auth.error', ['message' => trans('error.SystemError') . ', ' . trans('error.Visit') . '<a href="/logs" target="_blank">' . trans('error.log') . '</a>']);
-            }
-        }
+		// 捕获系统错误异常
+		if($exception instanceof ErrorException){
+			if($request->ajax()){
+				return response()->json(['status' => 'fail', 'data' => '', 'message' => 'System Error']);
+			}else{
+				return response()->view('auth.error', ['message' => trans('error.SystemError').', '.trans('error.Visit').'<a href="/logs" target="_blank">'.trans('error.log').'</a>']);
+			}
+		}
 
-        return parent::render($request, $exception);
-    }
+		return parent::render($request, $exception);
+	}
 }

La diferencia del archivo ha sido suprimido porque es demasiado grande
+ 0 - 633
app/Http/Controllers/AdminController.php


+ 249 - 247
app/Http/Controllers/Api/AlipayController.php

@@ -15,6 +15,7 @@ use App\Http\Models\User;
 use App\Http\Models\UserLabel;
 use App\Mail\sendUserInfo;
 use DB;
+use Exception;
 use Hash;
 use Illuminate\Http\Request;
 use Log;
@@ -29,251 +30,252 @@ use Mail;
  */
 class AlipayController extends Controller
 {
-    protected static $systemConfig;
-
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    // 接收GET请求
-    public function index(Request $request)
-    {
-        \Log::info("【支付宝国际】回调接口[GET]:" . var_export($request->all(), true) . '[' . getClientIp() . ']');
-        exit("【支付宝国际】接口正常");
-    }
-
-    // 接收POST请求
-    public function store(Request $request)
-    {
-        \Log::info("【支付宝国际】回调接口[POST]:" . var_export($request->all(), true));
-
-        $result = "fail";
-        $alipayNotify = new AlipayNotify(self::$systemConfig['alipay_sign_type'], self::$systemConfig['alipay_partner'], self::$systemConfig['alipay_key'], self::$systemConfig['alipay_private_key'], self::$systemConfig['alipay_public_key'], self::$systemConfig['alipay_transport']);
-
-        // 验证支付宝交易
-        $verify_result = $alipayNotify->verifyNotify();
-        if ($verify_result) { // 验证成功
-            $result = "success";
-            if ($_POST['trade_status'] == 'TRADE_FINISHED' || $_POST['trade_status'] == 'TRADE_SUCCESS') {
-                // 商户订单号
-                $data = [];
-                $data['out_trade_no'] = $request->input('out_trade_no');
-                // 支付宝交易号
-                $data['trade_no'] = $request->input('trade_no');
-                // 交易状态
-                $data['trade_status'] = $request->input('trade_status');
-                // 交易金额(这里是按照结算货币汇率的金额,和rmb_fee不相等)
-                $data['total_fee'] = $request->input('total_fee');
-
-                $this->tradePaid($data);
-            } else {
-                Log::info('AliPay-POST:交易失败[' . getClientIp() . ']');
-            }
-        } else {
-            Log::info('AliPay-POST:验证失败[' . getClientIp() . ']');
-        }
-
-        // 返回验证结果
-        exit($result);
-    }
-
-    // 交易支付
-    private function tradePaid($msg)
-    {
-        Log::info('【支付宝国际】回调交易支付');
-
-        // 获取未完成状态的订单防止重复增加时间
-        $payment = Payment::query()->with(['order', 'order.goods'])->where('status', 0)->where('order_sn', $msg['out_trade_no'])->first();
-        if (!$payment) {
-            Log::info('【支付宝国际】回调订单不存在');
-            return;
-        }
-
-        // 处理订单
-        DB::beginTransaction();
-        try {
-            // 如果支付单中没有用户信息则创建一个用户
-            if (!$payment->user_id) {
-                // 生成一个可用端口
-                $port = self::$systemConfig['is_rand_port'] ? Helpers::getRandPort() : Helpers::getOnlyPort();
-
-                $user = new User();
-                $user->username = '自动生成-' . $payment->order->email;
-                $user->password = Hash::make(makeRandStr());
-                $user->port = $port;
-                $user->passwd = makeRandStr();
-                $user->vmess_id = createGuid();
-                $user->enable = 1;
-                $user->method = Helpers::getDefaultMethod();
-                $user->protocol = Helpers::getDefaultProtocol();
-                $user->obfs = Helpers::getDefaultObfs();
-                $user->usage = 1;
-                $user->transfer_enable = 1; // 新创建的账号给1,防止定时任务执行时发现u + d >= transfer_enable被判为流量超限而封禁
-                $user->enable_time = date('Y-m-d');
-                $user->expire_time = date('Y-m-d', strtotime("+" . $payment->order->goods->days . " days"));
-                $user->reg_ip = getClientIp();
-                $user->referral_uid = 0;
-                $user->traffic_reset_day = 0;
-                $user->status = 1;
-                $user->save();
-
-                if ($user->id) {
-                    Order::query()->where('oid', $payment->oid)->update(['user_id' => $user->id]);
-                }
-            }
-
-            // 更新支付单
-            $payment->pay_way = 2; // 1-微信、2-支付宝
-            $payment->status = 1;
-            $payment->save();
-
-            // 更新订单
-            $order = Order::query()->with(['user'])->where('oid', $payment->oid)->first();
-            $order->status = 2;
-            $order->save();
-
-            $goods = Goods::query()->where('id', $order->goods_id)->first();
-
-            // 商品为流量或者套餐
-            if ($goods->type <= 2) {
-                // 如果买的是套餐,则先将之前购买的所有套餐置都无效,并扣掉之前所有套餐的流量,重置用户已用流量为0
-                if ($goods->type == 2) {
-                    $existOrderList = Order::query()
-                        ->with(['goods'])
-                        ->whereHas('goods', function ($q) {
-                            $q->where('type', 2);
-                        })
-                        ->where('user_id', $order->user_id)
-                        ->where('oid', '<>', $order->oid)
-                        ->where('is_expire', 0)
-                        ->where('status', 2)
-                        ->get();
-
-                    foreach ($existOrderList as $vo) {
-                        Order::query()->where('oid', $vo->oid)->update(['is_expire' => 1]);
-
-                        // 先判断,防止手动扣减过流量的用户流量被扣成负数
-                        if ($order->user->transfer_enable - $vo->goods->traffic * 1048576 <= 0) {
-                            // 写入用户流量变动记录
-                            Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, 0, 0, '[在线支付]用户购买套餐,先扣减之前套餐的流量(扣完)');
-
-                            User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
-                        } else {
-                            // 写入用户流量变动记录
-                            $user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
-                            Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable - $vo->goods->traffic * 1048576), '[在线支付]用户购买套餐,先扣减之前套餐的流量(未扣完)');
-
-                            User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0]);
-                            User::query()->where('id', $order->user_id)->decrement('transfer_enable', $vo->goods->traffic * 1048576);
-                        }
-                    }
-                }
-
-                // 写入用户流量变动记录
-                $user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
-                Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable + $goods->traffic * 1048576), '[在线支付]用户购买商品,加上流量');
-
-                // 把商品的流量加到账号上
-                User::query()->where('id', $order->user_id)->increment('transfer_enable', $goods->traffic * 1048576);
-
-                // 计算账号过期时间
-                if ($order->user->expire_time < date('Y-m-d', strtotime("+" . $goods->days . " days"))) {
-                    $expireTime = date('Y-m-d', strtotime("+" . $goods->days . " days"));
-                } else {
-                    $expireTime = $order->user->expire_time;
-                }
-
-                // 套餐就改流量重置日,流量包不改
-                if ($goods->type == 2) {
-                    if (date('m') == 2 && date('d') == 29) {
-                        $traffic_reset_day = 28;
-                    } else {
-                        $traffic_reset_day = date('d') == 31 ? 30 : abs(date('d'));
-                    }
-                    User::query()->where('id', $order->user_id)->update(['traffic_reset_day' => $traffic_reset_day, 'expire_time' => $expireTime, 'enable' => 1]);
-                } else {
-                    User::query()->where('id', $order->user_id)->update(['expire_time' => $expireTime, 'enable' => 1]);
-                }
-
-                // 写入用户标签
-                if ($goods->label) {
-                    // 用户默认标签
-                    $defaultLabels = [];
-                    if (self::$systemConfig['initial_labels_for_user']) {
-                        $defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
-                    }
-
-                    // 取出现有的标签
-                    $userLabels = UserLabel::query()->where('user_id', $order->user_id)->pluck('label_id')->toArray();
-                    $goodsLabels = GoodsLabel::query()->where('goods_id', $order->goods_id)->pluck('label_id')->toArray();
-
-                    // 标签去重
-                    $newUserLabels = array_values(array_unique(array_merge($userLabels, $goodsLabels, $defaultLabels)));
-
-                    // 删除用户所有标签
-                    UserLabel::query()->where('user_id', $order->user_id)->delete();
-
-                    // 生成标签
-                    foreach ($newUserLabels as $vo) {
-                        $obj = new UserLabel();
-                        $obj->user_id = $order->user_id;
-                        $obj->label_id = $vo;
-                        $obj->save();
-                    }
-                }
-
-                // 写入返利日志
-                if ($order->user->referral_uid) {
-                    $this->addReferralLog($order->user_id, $order->user->referral_uid, $order->oid, $order->amount, $order->amount * self::$systemConfig['referral_percent']);
-                }
-
-                // 取消重复返利
-                User::query()->where('id', $order->user_id)->update(['referral_uid' => 0]);
-            } elseif ($goods->type == 3) { // 商品为在线充值
-                User::query()->where('id', $order->user_id)->increment('balance', $goods->price * 100);
-
-                // 余额变动记录日志
-                $this->addUserBalanceLog($order->user_id, $order->oid, $order->user->balance, $order->user->balance + $goods->price, $goods->price, '用户在线充值');
-            }
-
-            // 自动提号机:如果order的email值不为空
-            if ($order->email) {
-                $title = '自动发送账号信息';
-                $content = [
-                    'order_sn'      => $order->order_sn,
-                    'goods_name'    => $order->goods->name,
-                    'goods_traffic' => flowAutoShow($order->goods->traffic * 1048576),
-                    'port'          => $order->user->port,
-                    'passwd'        => $order->user->passwd,
-                    'method'        => $order->user->method,
-                    //'protocol'       => $order->user->protocol,
-                    //'protocol_param' => $order->user->protocol_param,
-                    //'obfs'           => $order->user->obfs,
-                    //'obfs_param'     => $order->user->obfs_param,
-                    'created_at'    => $order->created_at->toDateTimeString(),
-                    'expire_at'     => $order->expire_at
-                ];
-
-                // 获取可用节点列表
-                $labels = UserLabel::query()->where('user_id', $order->user_id)->get()->pluck('label_id');
-                $nodeIds = SsNodeLabel::query()->whereIn('label_id', $labels)->get()->pluck('node_id');
-                $nodeList = SsNode::query()->whereIn('id', $nodeIds)->orderBy('sort', 'desc')->orderBy('id', 'desc')->get()->toArray();
-                $content['serverList'] = $nodeList;
-
-                $logId = Helpers::addEmailLog($order->email, $title, json_encode($content));
-                Mail::to($order->email)->send(new sendUserInfo($logId, $content));
-            }
-
-            DB::commit();
-        } catch (\Exception $e) {
-            DB::rollBack();
-            Log::info('【支付宝国际】回调更新支付单和订单异常:' . $e->getMessage());
-        }
-    }
-
-    public function show(Request $request)
-    {
-        exit('show');
-    }
+	protected static $systemConfig;
+
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	// 接收GET请求
+	public function index(Request $request)
+	{
+		Log::info("【支付宝国际】回调接口[GET]:".var_export($request->all(), TRUE).'['.getClientIp().']');
+		exit("【支付宝国际】接口正常");
+	}
+
+	// 接收POST请求
+	public function store(Request $request)
+	{
+		Log::info("【支付宝国际】回调接口[POST]:".var_export($request->all(), TRUE));
+
+		$result = "fail";
+		$alipayNotify = new AlipayNotify(self::$systemConfig['alipay_sign_type'], self::$systemConfig['alipay_partner'], self::$systemConfig['alipay_key'], self::$systemConfig['alipay_private_key'], self::$systemConfig['alipay_public_key'], self::$systemConfig['alipay_transport']);
+
+		// 验证支付宝交易
+		$verify_result = $alipayNotify->verifyNotify();
+		if($verify_result){ // 验证成功
+			$result = "success";
+			if($_POST['trade_status'] == 'TRADE_FINISHED' || $_POST['trade_status'] == 'TRADE_SUCCESS'){
+				// 商户订单号
+				$data = [];
+				$data['out_trade_no'] = $request->input('out_trade_no');
+				// 支付宝交易号
+				$data['trade_no'] = $request->input('trade_no');
+				// 交易状态
+				$data['trade_status'] = $request->input('trade_status');
+				// 交易金额(这里是按照结算货币汇率的金额,和rmb_fee不相等)
+				$data['total_fee'] = $request->input('total_fee');
+
+				$this->tradePaid($data);
+			}else{
+				Log::info('AliPay-POST:交易失败['.getClientIp().']');
+			}
+		}else{
+			Log::info('AliPay-POST:验证失败['.getClientIp().']');
+		}
+
+		// 返回验证结果
+		exit($result);
+	}
+
+	// 交易支付
+	private function tradePaid($msg)
+	{
+		Log::info('【支付宝国际】回调交易支付');
+
+		// 获取未完成状态的订单防止重复增加时间
+		$payment = Payment::query()->with(['order', 'order.goods'])->where('status', 0)->where('order_sn', $msg['out_trade_no'])->first();
+		if(!$payment){
+			Log::info('【支付宝国际】回调订单不存在');
+
+			return;
+		}
+
+		// 处理订单
+		DB::beginTransaction();
+		try{
+			// 如果支付单中没有用户信息则创建一个用户
+			if(!$payment->user_id){
+				// 生成一个可用端口
+				$port = self::$systemConfig['is_rand_port']? Helpers::getRandPort() : Helpers::getOnlyPort();
+
+				$user = new User();
+				$user->username = '自动生成-'.$payment->order->email;
+				$user->password = Hash::make(makeRandStr());
+				$user->port = $port;
+				$user->passwd = makeRandStr();
+				$user->vmess_id = createGuid();
+				$user->enable = 1;
+				$user->method = Helpers::getDefaultMethod();
+				$user->protocol = Helpers::getDefaultProtocol();
+				$user->obfs = Helpers::getDefaultObfs();
+				$user->usage = 1;
+				$user->transfer_enable = 1; // 新创建的账号给1,防止定时任务执行时发现u + d >= transfer_enable被判为流量超限而封禁
+				$user->enable_time = date('Y-m-d');
+				$user->expire_time = date('Y-m-d', strtotime("+".$payment->order->goods->days." days"));
+				$user->reg_ip = getClientIp();
+				$user->referral_uid = 0;
+				$user->traffic_reset_day = 0;
+				$user->status = 1;
+				$user->save();
+
+				if($user->id){
+					Order::query()->where('oid', $payment->oid)->update(['user_id' => $user->id]);
+				}
+			}
+
+			// 更新支付单
+			$payment->pay_way = 2; // 1-微信、2-支付宝
+			$payment->status = 1;
+			$payment->save();
+
+			// 更新订单
+			$order = Order::query()->with(['user'])->where('oid', $payment->oid)->first();
+			$order->status = 2;
+			$order->save();
+
+			$goods = Goods::query()->where('id', $order->goods_id)->first();
+
+			// 商品为流量或者套餐
+			if($goods->type <= 2){
+				// 如果买的是套餐,则先将之前购买的所有套餐置都无效,并扣掉之前所有套餐的流量,重置用户已用流量为0
+				if($goods->type == 2){
+					$existOrderList = Order::query()
+						->with(['goods'])
+						->whereHas('goods', function($q){
+							$q->where('type', 2);
+						})
+						->where('user_id', $order->user_id)
+						->where('oid', '<>', $order->oid)
+						->where('is_expire', 0)
+						->where('status', 2)
+						->get();
+
+					foreach($existOrderList as $vo){
+						Order::query()->where('oid', $vo->oid)->update(['is_expire' => 1]);
+
+						// 先判断,防止手动扣减过流量的用户流量被扣成负数
+						if($order->user->transfer_enable-$vo->goods->traffic*1048576 <= 0){
+							// 写入用户流量变动记录
+							Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, 0, 0, '[在线支付]用户购买套餐,先扣减之前套餐的流量(扣完)');
+
+							User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
+						}else{
+							// 写入用户流量变动记录
+							$user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
+							Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable-$vo->goods->traffic*1048576), '[在线支付]用户购买套餐,先扣减之前套餐的流量(未扣完)');
+
+							User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0]);
+							User::query()->where('id', $order->user_id)->decrement('transfer_enable', $vo->goods->traffic*1048576);
+						}
+					}
+				}
+
+				// 写入用户流量变动记录
+				$user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
+				Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable+$goods->traffic*1048576), '[在线支付]用户购买商品,加上流量');
+
+				// 把商品的流量加到账号上
+				User::query()->where('id', $order->user_id)->increment('transfer_enable', $goods->traffic*1048576);
+
+				// 计算账号过期时间
+				if($order->user->expire_time < date('Y-m-d', strtotime("+".$goods->days." days"))){
+					$expireTime = date('Y-m-d', strtotime("+".$goods->days." days"));
+				}else{
+					$expireTime = $order->user->expire_time;
+				}
+
+				// 套餐就改流量重置日,流量包不改
+				if($goods->type == 2){
+					if(date('m') == 2 && date('d') == 29){
+						$traffic_reset_day = 28;
+					}else{
+						$traffic_reset_day = date('d') == 31? 30 : abs(date('d'));
+					}
+					User::query()->where('id', $order->user_id)->update(['traffic_reset_day' => $traffic_reset_day, 'expire_time' => $expireTime, 'enable' => 1]);
+				}else{
+					User::query()->where('id', $order->user_id)->update(['expire_time' => $expireTime, 'enable' => 1]);
+				}
+
+				// 写入用户标签
+				if($goods->label){
+					// 用户默认标签
+					$defaultLabels = [];
+					if(self::$systemConfig['initial_labels_for_user']){
+						$defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
+					}
+
+					// 取出现有的标签
+					$userLabels = UserLabel::query()->where('user_id', $order->user_id)->pluck('label_id')->toArray();
+					$goodsLabels = GoodsLabel::query()->where('goods_id', $order->goods_id)->pluck('label_id')->toArray();
+
+					// 标签去重
+					$newUserLabels = array_values(array_unique(array_merge($userLabels, $goodsLabels, $defaultLabels)));
+
+					// 删除用户所有标签
+					UserLabel::query()->where('user_id', $order->user_id)->delete();
+
+					// 生成标签
+					foreach($newUserLabels as $vo){
+						$obj = new UserLabel();
+						$obj->user_id = $order->user_id;
+						$obj->label_id = $vo;
+						$obj->save();
+					}
+				}
+
+				// 写入返利日志
+				if($order->user->referral_uid){
+					$this->addReferralLog($order->user_id, $order->user->referral_uid, $order->oid, $order->amount, $order->amount*self::$systemConfig['referral_percent']);
+				}
+
+				// 取消重复返利
+				User::query()->where('id', $order->user_id)->update(['referral_uid' => 0]);
+			}elseif($goods->type == 3){ // 商品为在线充值
+				User::query()->where('id', $order->user_id)->increment('balance', $goods->price*100);
+
+				// 余额变动记录日志
+				$this->addUserBalanceLog($order->user_id, $order->oid, $order->user->balance, $order->user->balance+$goods->price, $goods->price, '用户在线充值');
+			}
+
+			// 自动提号机:如果order的email值不为空
+			if($order->email){
+				$title = '自动发送账号信息';
+				$content = [
+					'order_sn'      => $order->order_sn,
+					'goods_name'    => $order->goods->name,
+					'goods_traffic' => flowAutoShow($order->goods->traffic*1048576),
+					'port'          => $order->user->port,
+					'passwd'        => $order->user->passwd,
+					'method'        => $order->user->method,
+					//'protocol'       => $order->user->protocol,
+					//'protocol_param' => $order->user->protocol_param,
+					//'obfs'           => $order->user->obfs,
+					//'obfs_param'     => $order->user->obfs_param,
+					'created_at'    => $order->created_at->toDateTimeString(),
+					'expire_at'     => $order->expire_at
+				];
+
+				// 获取可用节点列表
+				$labels = UserLabel::query()->where('user_id', $order->user_id)->get()->pluck('label_id');
+				$nodeIds = SsNodeLabel::query()->whereIn('label_id', $labels)->get()->pluck('node_id');
+				$nodeList = SsNode::query()->whereIn('id', $nodeIds)->orderBy('sort', 'desc')->orderBy('id', 'desc')->get()->toArray();
+				$content['serverList'] = $nodeList;
+
+				$logId = Helpers::addEmailLog($order->email, $title, json_encode($content));
+				Mail::to($order->email)->send(new sendUserInfo($logId, $content));
+			}
+
+			DB::commit();
+		} catch(Exception $e){
+			DB::rollBack();
+			Log::info('【支付宝国际】回调更新支付单和订单异常:'.$e->getMessage());
+		}
+	}
+
+	public function show(Request $request)
+	{
+		exit('show');
+	}
 }

+ 268 - 266
app/Http/Controllers/Api/F2fpayController.php

@@ -14,6 +14,7 @@ use App\Http\Models\User;
 use App\Http\Models\UserLabel;
 use App\Mail\sendUserInfo;
 use DB;
+use Exception;
 use Hash;
 use Illuminate\Http\Request;
 use Log;
@@ -30,270 +31,271 @@ use Payment\Common\PayException;
  */
 class F2fpayController extends Controller
 {
-    protected static $systemConfig;
-
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    // 接收GET请求
-    public function index(Request $request)
-    {
-        \Log::info("【支付宝当面付】回调接口[GET]:" . var_export($request->all(), true) . '[' . getClientIp() . ']');
-        exit("【支付宝当面付】接口正常");
-    }
-
-    // 接收POST请求
-    public function store(Request $request)
-    {
-        \Log::info("【支付宝当面付】回调接口[POST]:" . var_export($request->all(), true));
-
-        $result = "fail";
-
-        try {
-            $verify_result = Query::run('ali_charge', [
-                'use_sandbox'     => false,
-                "partner"         => self::$systemConfig['f2fpay_app_id'],
-                'app_id'          => self::$systemConfig['f2fpay_app_id'],
-                'sign_type'       => 'RSA2',
-                'ali_public_key'  => self::$systemConfig['f2fpay_public_key'],
-                'rsa_private_key' => self::$systemConfig['f2fpay_private_key'],
-                'notify_url'      => self::$systemConfig['website_url'] . "/api/f2fpay", // 异步回调接口
-                'return_url'      => self::$systemConfig['website_url'],
-                'return_raw'      => false
-            ], [
-                'out_trade_no' => $request->input('out_trade_no'),
-                'trade_no'     => $request->input('trade_no'),
-            ]);
-
-            \Log::info("【支付宝当面付】回调验证查询:" . var_export($verify_result, true));
-        } catch (PayException $e) {
-            \Log::info("【支付宝当面付】回调验证查询出错:" . var_export($e->errorMessage(), true));
-            exit($result);
-        }
-
-        if ($verify_result['is_success'] == 'T') { // 验证成功
-            $result = "success";
-            if ($_POST['trade_status'] == 'TRADE_FINISHED' || $_POST['trade_status'] == 'TRADE_SUCCESS') {
-                // 商户订单号
-                $data = [];
-                $data['out_trade_no'] = $request->input('out_trade_no');
-                // 支付宝交易号
-                $data['trade_no'] = $request->input('trade_no');
-                // 交易状态
-                $data['trade_status'] = $request->input('trade_status');
-                // 交易金额(这里是按照结算货币汇率的金额,和rmb_fee不相等)
-                $data['total_amount'] = $request->input('total_amount');
-
-                $this->tradePaid($data);
-            } else {
-                Log::info('支付宝当面付-POST:交易失败[' . getClientIp() . ']');
-            }
-        } else {
-            Log::info('支付宝当面付-POST:验证失败[' . getClientIp() . ']');
-        }
-
-        // 返回验证结果
-        exit($result);
-    }
-
-    // 交易支付
-    private function tradePaid($msg)
-    {
-        Log::info('【支付宝当面付】回调交易支付');
-
-        // 获取未完成状态的订单防止重复增加时间
-        $payment = Payment::query()->with(['order', 'order.goods'])->where('status', 0)->where('order_sn', $msg['out_trade_no'])->first();
-        if (!$payment) {
-            Log::info('【支付宝当面付】回调订单不存在');
-            return;
-        }
-
-        // 处理订单
-        DB::beginTransaction();
-        try {
-            // 如果支付单中没有用户信息则创建一个用户
-            if (!$payment->user_id) {
-                // 生成一个可用端口
-                $port = self::$systemConfig['is_rand_port'] ? Helpers::getRandPort() : Helpers::getOnlyPort();
-
-                $user = new User();
-                $user->username = '自动生成-' . $payment->order->email;
-                $user->password = Hash::make(makeRandStr());
-                $user->port = $port;
-                $user->passwd = makeRandStr();
-                $user->vmess_id = createGuid();
-                $user->enable = 1;
-                $user->method = Helpers::getDefaultMethod();
-                $user->protocol = Helpers::getDefaultProtocol();
-                $user->obfs = Helpers::getDefaultObfs();
-                $user->usage = 1;
-                $user->transfer_enable = 1; // 新创建的账号给1,防止定时任务执行时发现u + d >= transfer_enable被判为流量超限而封禁
-                $user->enable_time = date('Y-m-d');
-                $user->expire_time = date('Y-m-d', strtotime("+" . $payment->order->goods->days . " days"));
-                $user->reg_ip = getClientIp();
-                $user->referral_uid = 0;
-                $user->traffic_reset_day = 0;
-                $user->status = 1;
-                $user->save();
-
-                if ($user->id) {
-                    Order::query()->where('oid', $payment->oid)->update(['user_id' => $user->id]);
-                }
-            }
-
-            // 更新支付单
-            $payment->pay_way = 2; // 1-微信、2-支付宝
-            $payment->status = 1;
-            $payment->save();
-
-            // 更新订单
-            $order = Order::query()->with(['user'])->where('oid', $payment->oid)->first();
-            $order->status = 2;
-            $order->save();
-
-            $goods = Goods::query()->where('id', $order->goods_id)->first();
-
-            // 商品为流量或者套餐
-            if ($goods->type <= 2) {
-                // 如果买的是套餐,则先将之前购买的所有套餐置都无效,并扣掉之前所有套餐的流量,重置用户已用流量为0
-                if ($goods->type == 2) {
-                    $existOrderList = Order::query()
-                        ->with(['goods'])
-                        ->whereHas('goods', function ($q) {
-                            $q->where('type', 2);
-                        })
-                        ->where('user_id', $order->user_id)
-                        ->where('oid', '<>', $order->oid)
-                        ->where('is_expire', 0)
-                        ->where('status', 2)
-                        ->get();
-
-                    foreach ($existOrderList as $vo) {
-                        Order::query()->where('oid', $vo->oid)->update(['is_expire' => 1]);
-
-                        // 先判断,防止手动扣减过流量的用户流量被扣成负数
-                        if ($order->user->transfer_enable - $vo->goods->traffic * 1048576 <= 0) {
-                            // 写入用户流量变动记录
-                            Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, 0, 0, '[在线支付]用户购买套餐,先扣减之前套餐的流量(扣完)');
-
-                            User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
-                        } else {
-                            // 写入用户流量变动记录
-                            $user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
-                            Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable - $vo->goods->traffic * 1048576), '[在线支付]用户购买套餐,先扣减之前套餐的流量(未扣完)');
-
-                            User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0]);
-                            User::query()->where('id', $order->user_id)->decrement('transfer_enable', $vo->goods->traffic * 1048576);
-                        }
-                    }
-                }
-
-                // 写入用户流量变动记录
-                $user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
-                Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable + $goods->traffic * 1048576), '[在线支付]用户购买商品,加上流量');
-
-                // 把商品的流量加到账号上
-                User::query()->where('id', $order->user_id)->increment('transfer_enable', $goods->traffic * 1048576);
-
-                // 计算账号过期时间
-                if ($order->user->expire_time < date('Y-m-d', strtotime("+" . $goods->days . " days"))) {
-                    $expireTime = date('Y-m-d', strtotime("+" . $goods->days . " days"));
-                } else {
-                    $expireTime = $order->user->expire_time;
-                }
-
-                // 套餐就改流量重置日,流量包不改
-                if ($goods->type == 2) {
-                    if (date('m') == 2 && date('d') == 29) {
-                        $traffic_reset_day = 28;
-                    } else {
-                        $traffic_reset_day = date('d') == 31 ? 30 : abs(date('d'));
-                    }
-                    User::query()->where('id', $order->user_id)->update(['traffic_reset_day' => $traffic_reset_day, 'expire_time' => $expireTime, 'enable' => 1]);
-                } else {
-                    User::query()->where('id', $order->user_id)->update(['expire_time' => $expireTime, 'enable' => 1]);
-                }
-
-                // 写入用户标签
-                if ($goods->label) {
-                    // 用户默认标签
-                    $defaultLabels = [];
-                    if (self::$systemConfig['initial_labels_for_user']) {
-                        $defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
-                    }
-
-                    // 取出现有的标签
-                    $userLabels = UserLabel::query()->where('user_id', $order->user_id)->pluck('label_id')->toArray();
-                    $goodsLabels = GoodsLabel::query()->where('goods_id', $order->goods_id)->pluck('label_id')->toArray();
-
-                    // 标签去重
-                    $newUserLabels = array_values(array_unique(array_merge($userLabels, $goodsLabels, $defaultLabels)));
-
-                    // 删除用户所有标签
-                    UserLabel::query()->where('user_id', $order->user_id)->delete();
-
-                    // 生成标签
-                    foreach ($newUserLabels as $vo) {
-                        $obj = new UserLabel();
-                        $obj->user_id = $order->user_id;
-                        $obj->label_id = $vo;
-                        $obj->save();
-                    }
-                }
-
-                // 写入返利日志
-                if ($order->user->referral_uid) {
-                    $this->addReferralLog($order->user_id, $order->user->referral_uid, $order->oid, $order->amount, $order->amount * self::$systemConfig['referral_percent']);
-                }
-
-                // 取消重复返利
-                User::query()->where('id', $order->user_id)->update(['referral_uid' => 0]);
-            } elseif ($goods->type == 3) { // 商品为在线充值
-                User::query()->where('id', $order->user_id)->increment('balance', $goods->price * 100);
-
-                // 余额变动记录日志
-                $this->addUserBalanceLog($order->user_id, $order->oid, $order->user->balance, $order->user->balance + $goods->price, $goods->price, '用户在线充值');
-            }
-
-            // 自动提号机:如果order的email值不为空
-            if ($order->email) {
-                $title = '自动发送账号信息';
-                $content = [
-                    'order_sn'      => $order->order_sn,
-                    'goods_name'    => $order->goods->name,
-                    'goods_traffic' => flowAutoShow($order->goods->traffic * 1048576),
-                    'port'          => $order->user->port,
-                    'passwd'        => $order->user->passwd,
-                    'method'        => $order->user->method,
-                    //'protocol'       => $order->user->protocol,
-                    //'protocol_param' => $order->user->protocol_param,
-                    //'obfs'           => $order->user->obfs,
-                    //'obfs_param'     => $order->user->obfs_param,
-                    'created_at'    => $order->created_at->toDateTimeString(),
-                    'expire_at'     => $order->expire_at
-                ];
-
-                // 获取可用节点列表
-                $labels = UserLabel::query()->where('user_id', $order->user_id)->get()->pluck('label_id');
-                $nodeIds = SsNodeLabel::query()->whereIn('label_id', $labels)->get()->pluck('node_id');
-                $nodeList = SsNode::query()->whereIn('id', $nodeIds)->orderBy('sort', 'desc')->orderBy('id', 'desc')->get()->toArray();
-                $content['serverList'] = $nodeList;
-
-                $logId = Helpers::addEmailLog($order->email, $title, json_encode($content));
-                Mail::to($order->email)->send(new sendUserInfo($logId, $content));
-            }
-
-            DB::commit();
-        } catch (\Exception $e) {
-            DB::rollBack();
-            Log::info('【支付宝当面付】回调更新支付单和订单异常:' . $e->getMessage());
-        }
-    }
-
-    public function show(Request $request)
-    {
-        exit('show');
-    }
+	protected static $systemConfig;
+
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	// 接收GET请求
+	public function index(Request $request)
+	{
+		Log::info("【支付宝当面付】回调接口[GET]:".var_export($request->all(), TRUE).'['.getClientIp().']');
+		exit("【支付宝当面付】接口正常");
+	}
+
+	// 接收POST请求
+	public function store(Request $request)
+	{
+		Log::info("【支付宝当面付】回调接口[POST]:".var_export($request->all(), TRUE));
+
+		$result = "fail";
+
+		try{
+			$verify_result = Query::run('ali_charge', [
+				'use_sandbox'     => FALSE,
+				"partner"         => self::$systemConfig['f2fpay_app_id'],
+				'app_id'          => self::$systemConfig['f2fpay_app_id'],
+				'sign_type'       => 'RSA2',
+				'ali_public_key'  => self::$systemConfig['f2fpay_public_key'],
+				'rsa_private_key' => self::$systemConfig['f2fpay_private_key'],
+				'notify_url'      => self::$systemConfig['website_url']."/api/f2fpay", // 异步回调接口
+				'return_url'      => self::$systemConfig['website_url'],
+				'return_raw'      => FALSE
+			], [
+				'out_trade_no' => $request->input('out_trade_no'),
+				'trade_no'     => $request->input('trade_no'),
+			]);
+
+			Log::info("【支付宝当面付】回调验证查询:".var_export($verify_result, TRUE));
+		} catch(PayException $e){
+			Log::info("【支付宝当面付】回调验证查询出错:".var_export($e->errorMessage(), TRUE));
+			exit($result);
+		}
+
+		if($verify_result['is_success'] == 'T'){ // 验证成功
+			$result = "success";
+			if($_POST['trade_status'] == 'TRADE_FINISHED' || $_POST['trade_status'] == 'TRADE_SUCCESS'){
+				// 商户订单号
+				$data = [];
+				$data['out_trade_no'] = $request->input('out_trade_no');
+				// 支付宝交易号
+				$data['trade_no'] = $request->input('trade_no');
+				// 交易状态
+				$data['trade_status'] = $request->input('trade_status');
+				// 交易金额(这里是按照结算货币汇率的金额,和rmb_fee不相等)
+				$data['total_amount'] = $request->input('total_amount');
+
+				$this->tradePaid($data);
+			}else{
+				Log::info('支付宝当面付-POST:交易失败['.getClientIp().']');
+			}
+		}else{
+			Log::info('支付宝当面付-POST:验证失败['.getClientIp().']');
+		}
+
+		// 返回验证结果
+		exit($result);
+	}
+
+	// 交易支付
+	private function tradePaid($msg)
+	{
+		Log::info('【支付宝当面付】回调交易支付');
+
+		// 获取未完成状态的订单防止重复增加时间
+		$payment = Payment::query()->with(['order', 'order.goods'])->where('status', 0)->where('order_sn', $msg['out_trade_no'])->first();
+		if(!$payment){
+			Log::info('【支付宝当面付】回调订单不存在');
+
+			return;
+		}
+
+		// 处理订单
+		DB::beginTransaction();
+		try{
+			// 如果支付单中没有用户信息则创建一个用户
+			if(!$payment->user_id){
+				// 生成一个可用端口
+				$port = self::$systemConfig['is_rand_port']? Helpers::getRandPort() : Helpers::getOnlyPort();
+
+				$user = new User();
+				$user->username = '自动生成-'.$payment->order->email;
+				$user->password = Hash::make(makeRandStr());
+				$user->port = $port;
+				$user->passwd = makeRandStr();
+				$user->vmess_id = createGuid();
+				$user->enable = 1;
+				$user->method = Helpers::getDefaultMethod();
+				$user->protocol = Helpers::getDefaultProtocol();
+				$user->obfs = Helpers::getDefaultObfs();
+				$user->usage = 1;
+				$user->transfer_enable = 1; // 新创建的账号给1,防止定时任务执行时发现u + d >= transfer_enable被判为流量超限而封禁
+				$user->enable_time = date('Y-m-d');
+				$user->expire_time = date('Y-m-d', strtotime("+".$payment->order->goods->days." days"));
+				$user->reg_ip = getClientIp();
+				$user->referral_uid = 0;
+				$user->traffic_reset_day = 0;
+				$user->status = 1;
+				$user->save();
+
+				if($user->id){
+					Order::query()->where('oid', $payment->oid)->update(['user_id' => $user->id]);
+				}
+			}
+
+			// 更新支付单
+			$payment->pay_way = 2; // 1-微信、2-支付宝
+			$payment->status = 1;
+			$payment->save();
+
+			// 更新订单
+			$order = Order::query()->with(['user'])->where('oid', $payment->oid)->first();
+			$order->status = 2;
+			$order->save();
+
+			$goods = Goods::query()->where('id', $order->goods_id)->first();
+
+			// 商品为流量或者套餐
+			if($goods->type <= 2){
+				// 如果买的是套餐,则先将之前购买的所有套餐置都无效,并扣掉之前所有套餐的流量,重置用户已用流量为0
+				if($goods->type == 2){
+					$existOrderList = Order::query()
+						->with(['goods'])
+						->whereHas('goods', function($q){
+							$q->where('type', 2);
+						})
+						->where('user_id', $order->user_id)
+						->where('oid', '<>', $order->oid)
+						->where('is_expire', 0)
+						->where('status', 2)
+						->get();
+
+					foreach($existOrderList as $vo){
+						Order::query()->where('oid', $vo->oid)->update(['is_expire' => 1]);
+
+						// 先判断,防止手动扣减过流量的用户流量被扣成负数
+						if($order->user->transfer_enable-$vo->goods->traffic*1048576 <= 0){
+							// 写入用户流量变动记录
+							Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, 0, 0, '[在线支付]用户购买套餐,先扣减之前套餐的流量(扣完)');
+
+							User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
+						}else{
+							// 写入用户流量变动记录
+							$user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
+							Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable-$vo->goods->traffic*1048576), '[在线支付]用户购买套餐,先扣减之前套餐的流量(未扣完)');
+
+							User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0]);
+							User::query()->where('id', $order->user_id)->decrement('transfer_enable', $vo->goods->traffic*1048576);
+						}
+					}
+				}
+
+				// 写入用户流量变动记录
+				$user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
+				Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable+$goods->traffic*1048576), '[在线支付]用户购买商品,加上流量');
+
+				// 把商品的流量加到账号上
+				User::query()->where('id', $order->user_id)->increment('transfer_enable', $goods->traffic*1048576);
+
+				// 计算账号过期时间
+				if($order->user->expire_time < date('Y-m-d', strtotime("+".$goods->days." days"))){
+					$expireTime = date('Y-m-d', strtotime("+".$goods->days." days"));
+				}else{
+					$expireTime = $order->user->expire_time;
+				}
+
+				// 套餐就改流量重置日,流量包不改
+				if($goods->type == 2){
+					if(date('m') == 2 && date('d') == 29){
+						$traffic_reset_day = 28;
+					}else{
+						$traffic_reset_day = date('d') == 31? 30 : abs(date('d'));
+					}
+					User::query()->where('id', $order->user_id)->update(['traffic_reset_day' => $traffic_reset_day, 'expire_time' => $expireTime, 'enable' => 1]);
+				}else{
+					User::query()->where('id', $order->user_id)->update(['expire_time' => $expireTime, 'enable' => 1]);
+				}
+
+				// 写入用户标签
+				if($goods->label){
+					// 用户默认标签
+					$defaultLabels = [];
+					if(self::$systemConfig['initial_labels_for_user']){
+						$defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
+					}
+
+					// 取出现有的标签
+					$userLabels = UserLabel::query()->where('user_id', $order->user_id)->pluck('label_id')->toArray();
+					$goodsLabels = GoodsLabel::query()->where('goods_id', $order->goods_id)->pluck('label_id')->toArray();
+
+					// 标签去重
+					$newUserLabels = array_values(array_unique(array_merge($userLabels, $goodsLabels, $defaultLabels)));
+
+					// 删除用户所有标签
+					UserLabel::query()->where('user_id', $order->user_id)->delete();
+
+					// 生成标签
+					foreach($newUserLabels as $vo){
+						$obj = new UserLabel();
+						$obj->user_id = $order->user_id;
+						$obj->label_id = $vo;
+						$obj->save();
+					}
+				}
+
+				// 写入返利日志
+				if($order->user->referral_uid){
+					$this->addReferralLog($order->user_id, $order->user->referral_uid, $order->oid, $order->amount, $order->amount*self::$systemConfig['referral_percent']);
+				}
+
+				// 取消重复返利
+				User::query()->where('id', $order->user_id)->update(['referral_uid' => 0]);
+			}elseif($goods->type == 3){ // 商品为在线充值
+				User::query()->where('id', $order->user_id)->increment('balance', $goods->price*100);
+
+				// 余额变动记录日志
+				$this->addUserBalanceLog($order->user_id, $order->oid, $order->user->balance, $order->user->balance+$goods->price, $goods->price, '用户在线充值');
+			}
+
+			// 自动提号机:如果order的email值不为空
+			if($order->email){
+				$title = '自动发送账号信息';
+				$content = [
+					'order_sn'      => $order->order_sn,
+					'goods_name'    => $order->goods->name,
+					'goods_traffic' => flowAutoShow($order->goods->traffic*1048576),
+					'port'          => $order->user->port,
+					'passwd'        => $order->user->passwd,
+					'method'        => $order->user->method,
+					//'protocol'       => $order->user->protocol,
+					//'protocol_param' => $order->user->protocol_param,
+					//'obfs'           => $order->user->obfs,
+					//'obfs_param'     => $order->user->obfs_param,
+					'created_at'    => $order->created_at->toDateTimeString(),
+					'expire_at'     => $order->expire_at
+				];
+
+				// 获取可用节点列表
+				$labels = UserLabel::query()->where('user_id', $order->user_id)->get()->pluck('label_id');
+				$nodeIds = SsNodeLabel::query()->whereIn('label_id', $labels)->get()->pluck('node_id');
+				$nodeList = SsNode::query()->whereIn('id', $nodeIds)->orderBy('sort', 'desc')->orderBy('id', 'desc')->get()->toArray();
+				$content['serverList'] = $nodeList;
+
+				$logId = Helpers::addEmailLog($order->email, $title, json_encode($content));
+				Mail::to($order->email)->send(new sendUserInfo($logId, $content));
+			}
+
+			DB::commit();
+		} catch(Exception $e){
+			DB::rollBack();
+			Log::info('【支付宝当面付】回调更新支付单和订单异常:'.$e->getMessage());
+		}
+	}
+
+	public function show(Request $request)
+	{
+		exit('show');
+	}
 }

+ 125 - 124
app/Http/Controllers/Api/LoginController.php

@@ -10,6 +10,7 @@ use App\Http\Models\UserSubscribe;
 use App\Http\Models\UserSubscribeLog;
 use Cache;
 use DB;
+use Exception;
 use Hash;
 use Illuminate\Http\Request;
 use Response;
@@ -23,128 +24,128 @@ use Response;
  */
 class LoginController extends Controller
 {
-    protected static $systemConfig;
-
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    // 登录返回订阅信息
-    public function login(Request $request)
-    {
-        $username = trim($request->input('username'));
-        $password = trim($request->input('password'));
-        $cacheKey = 'request_times_' . md5(getClientIp());
-
-        if (!$username || !$password) {
-            Cache::increment($cacheKey);
-
-            return Response::json(['status' => 'fail', 'data' => [], 'message' => '请输入用户名和密码']);
-        }
-
-        // 连续请求失败15次,则封IP一小时
-        if (Cache::has($cacheKey)) {
-            if (Cache::get($cacheKey) >= 15) {
-                return Response::json(['status' => 'fail', 'data' => [], 'message' => '请求失败超限,禁止访问1小时']);
-            }
-        } else {
-            Cache::put($cacheKey, 1, 60);
-        }
-
-        $user = User::query()->where('username', $username)->where('status', '>=', 0)->first();
-        if (!$user) {
-            Cache::increment($cacheKey);
-
-            return Response::json(['status' => 'fail', 'data' => [], 'message' => '账号不存在或已被禁用']);
-        } elseif (!Hash::check($password, $user->password)) {
-            return Response::json(['status' => 'fail', 'data' => [], 'message' => '用户名或密码错误']);
-        }
-
-        DB::beginTransaction();
-        try {
-            // 如果未生成过订阅链接则生成一个
-            $subscribe = UserSubscribe::query()->where('user_id', $user->id)->first();
-
-            // 更新订阅链接访问次数
-            $subscribe->increment('times', 1);
-
-            // 记录每次请求
-            $this->log($subscribe->id, getClientIp(), 'API访问');
-
-            // 订阅链接
-            $url = self::$systemConfig['subscribe_domain'] ? self::$systemConfig['subscribe_domain'] : self::$systemConfig['website_url'];
-
-            // 节点列表
-            $userLabelIds = UserLabel::query()->where('user_id', $user->id)->pluck('label_id');
-            if (empty($userLabelIds)) {
-                return Response::json(['status' => 'fail', 'message' => '', 'data' => []]);
-            }
-
-            $nodeList = DB::table('ss_node')
-                ->selectRaw('ss_node.*')
-                ->leftJoin('ss_node_label', 'ss_node.id', '=', 'ss_node_label.node_id')
-                ->whereIn('ss_node_label.label_id', $userLabelIds)
-                ->where('ss_node.status', 1)
-                ->groupBy('ss_node.id')
-                ->orderBy('ss_node.sort', 'desc')
-                ->orderBy('ss_node.id', 'asc')
-                ->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' => 'ssrpanel',
-                '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', 'data' => [], 'message' => '登录失败']);
-        }
-    }
-
-    // 写入订阅访问日志
-    private function log($subscribeId, $ip, $headers)
-    {
-        $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();
-    }
+	protected static $systemConfig;
+
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	// 登录返回订阅信息
+	public function login(Request $request)
+	{
+		$username = trim($request->input('username'));
+		$password = trim($request->input('password'));
+		$cacheKey = 'request_times_'.md5(getClientIp());
+
+		if(!$username || !$password){
+			Cache::increment($cacheKey);
+
+			return Response::json(['status' => 'fail', 'data' => [], 'message' => '请输入用户名和密码']);
+		}
+
+		// 连续请求失败15次,则封IP一小时
+		if(Cache::has($cacheKey)){
+			if(Cache::get($cacheKey) >= 15){
+				return Response::json(['status' => 'fail', 'data' => [], 'message' => '请求失败超限,禁止访问1小时']);
+			}
+		}else{
+			Cache::put($cacheKey, 1, 60);
+		}
+
+		$user = User::query()->where('username', $username)->where('status', '>=', 0)->first();
+		if(!$user){
+			Cache::increment($cacheKey);
+
+			return Response::json(['status' => 'fail', 'data' => [], 'message' => '账号不存在或已被禁用']);
+		}elseif(!Hash::check($password, $user->password)){
+			return Response::json(['status' => 'fail', 'data' => [], 'message' => '用户名或密码错误']);
+		}
+
+		DB::beginTransaction();
+		try{
+			// 如果未生成过订阅链接则生成一个
+			$subscribe = UserSubscribe::query()->where('user_id', $user->id)->first();
+
+			// 更新订阅链接访问次数
+			$subscribe->increment('times', 1);
+
+			// 记录每次请求
+			$this->log($subscribe->id, getClientIp(), 'API访问');
+
+			// 订阅链接
+			$url = self::$systemConfig['subscribe_domain']? self::$systemConfig['subscribe_domain'] : self::$systemConfig['website_url'];
+
+			// 节点列表
+			$userLabelIds = UserLabel::query()->where('user_id', $user->id)->pluck('label_id');
+			if(empty($userLabelIds)){
+				return Response::json(['status' => 'fail', 'message' => '', 'data' => []]);
+			}
+
+			$nodeList = DB::table('ss_node')
+				->selectRaw('ss_node.*')
+				->leftJoin('ss_node_label', 'ss_node.id', '=', 'ss_node_label.node_id')
+				->whereIn('ss_node_label.label_id', $userLabelIds)
+				->where('ss_node.status', 1)
+				->groupBy('ss_node.id')
+				->orderBy('ss_node.sort', 'desc')
+				->orderBy('ss_node.id', 'asc')
+				->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' => 'ssrpanel',
+				'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', 'data' => [], 'message' => '登录失败']);
+		}
+	}
+
+	// 写入订阅访问日志
+	private function log($subscribeId, $ip, $headers)
+	{
+		$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();
+	}
 }

+ 57 - 56
app/Http/Controllers/Api/PingController.php

@@ -3,6 +3,7 @@
 namespace App\Http\Controllers\Api;
 
 use App\Http\Controllers\Controller;
+use Exception;
 use Illuminate\Http\Request;
 use Log;
 
@@ -15,67 +16,67 @@ use Log;
  */
 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);
+	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();
-        }
+		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']);
-        }
+		// 验证TOKEN,防止滥用
+		if(env('API_TOKEN') != $token){
+			return response()->json(['status' => 0, 'message' => 'token invalid']);
+		}
 
-        // 如果不是IPv4
-        if (false === filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)) {
-            // 如果是IPv6
-            if (filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
-                $host = '[' . $host . ']';
-            }
-        }
+		// 如果不是IPv4
+		if(FALSE === filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4)){
+			// 如果是IPv6
+			if(filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_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';
-            }
+		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);
+			fclose($fp);
 
-            return response()->json(['status' => $ret, 'message' => $message]);
-        } catch (\Exception $e) {
-            Log::info($e);
+			return response()->json(['status' => $ret, 'message' => $message]);
+		} catch(Exception $e){
+			Log::info($e);
 
-            return response()->json(['status' => 0, 'message' => 'port close']);
-        }
-    }
+			return response()->json(['status' => 0, 'message' => 'port close']);
+		}
+	}
 }

+ 362 - 361
app/Http/Controllers/Api/YzyController.php

@@ -15,6 +15,7 @@ use App\Http\Models\User;
 use App\Http\Models\UserLabel;
 use App\Mail\sendUserInfo;
 use DB;
+use Exception;
 use Hash;
 use Illuminate\Http\Request;
 use Log;
@@ -29,365 +30,365 @@ use Mail;
  */
 class YzyController extends Controller
 {
-    protected static $systemConfig;
-
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    // 接收GET请求
-    public function index(Request $request)
-    {
-        \Log::info("【有赞云】回调接口[GET]:" . var_export($request->all(), true) . '[' . getClientIp() . ']');
-        exit("【有赞云】接口正常");
-    }
-
-    // 接收POST请求
-    public function store(Request $request)
-    {
-        \Log::info("【有赞云】回调接口[POST]:" . var_export($request->all(), true));
-
-        $json = file_get_contents('php://input');
-        $data = json_decode($json, true);
-        if (!$data) {
-            Log::info('YZY-POST:回调数据无法解析,可能是非法请求[' . getClientIp() . ']');
-            exit();
-        }
-
-        // 判断消息是否合法
-        $msg = $data['msg'];
-        $sign_string = self::$systemConfig['youzan_client_id'] . "" . $msg . "" . self::$systemConfig['youzan_client_secret'];
-        $sign = md5($sign_string);
-        if ($sign != $data['sign']) {
-            Log::info('本地签名:' . $sign_string . ' | 远程签名:' . $data['sign']);
-            Log::info('YZY-POST:回调数据签名错误,可能是非法请求[' . getClientIp() . ']');
-            exit();
-        } else {
-            // 返回请求成功标识给有赞
-            var_dump(["code" => 0, "msg" => "success"]);
-        }
-
-        // 容错
-        if (!isset($data['kdt_name'])) {
-            Log::info("【有赞云】回调数据解析错误,请检查有赞支付设置是否与有赞控制台中的信息保持一致。如果还出现此提示,请执行一遍php artisan cache:clear命令");
-            exit();
-        }
-
-        // 先写入回调日志
-        $this->callbackLog($data['client_id'], $data['id'], $data['kdt_id'], $data['kdt_name'], $data['mode'], $data['msg'], $data['sendCount'], $data['sign'], $data['status'], $data['test'], $data['type'], $data['version']);
-
-        // msg内容经过 urlencode 编码,进行解码
-        $msg = json_decode(urldecode($msg), true);
-
-        switch ($data['type']) {
-            case 'trade_TradePaid':
-                $this->tradePaid($msg);
-                break;
-            case 'trade_TradeCreate':
-                $this->tradeCreate($msg);
-                break;
-            case 'trade_TradeClose':
-                $this->tradeClose($msg);
-                break;
-            case 'trade_TradeSuccess':
-                $this->tradeSuccess($msg);
-                break;
-            case 'trade_TradePartlySellerShip':
-                $this->tradePartlySellerShip($msg);
-                break;
-            case 'trade_TradeSellerShip':
-                $this->tradeSellerShip($msg);
-                break;
-            case 'trade_TradeBuyerPay':
-                $this->tradeBuyerPay($msg);
-                break;
-            case 'trade_TradeMemoModified':
-                $this->tradeMemoModified($msg);
-                break;
-            default:
-                Log::info('【有赞云】回调无法识别,可能是没有启用[交易消息V3]接口,请到有赞云控制台启用消息推送服务');
-                exit();
-        }
-
-        exit();
-    }
-
-    // 交易支付
-    private function tradePaid($msg)
-    {
-        Log::info('【有赞云】回调交易支付');
-
-        $payment = Payment::query()->with(['order', 'order.goods'])->where('qr_id', $msg['qr_info']['qr_id'])->first();
-        if (!$payment) {
-            Log::info('【有赞云】回调订单不存在');
-            exit();
-        }
-
-        if ($payment->status != '0') {
-            Log::info('【有赞云】回调订单状态不正确');
-            exit();
-        }
-
-        // 处理订单
-        DB::beginTransaction();
-        try {
-            // 如果支付单中没有用户信息则创建一个用户
-            if (!$payment->user_id) {
-                // 生成一个可用端口
-                $port = self::$systemConfig['is_rand_port'] ? Helpers::getRandPort() : Helpers::getOnlyPort();
-
-                $user = new User();
-                $user->username = '自动生成-' . $payment->order->email;
-                $user->password = Hash::make(makeRandStr());
-                $user->port = $port;
-                $user->passwd = makeRandStr();
-                $user->vmess_id = createGuid();
-                $user->enable = 1;
-                $user->method = Helpers::getDefaultMethod();
-                $user->protocol = Helpers::getDefaultProtocol();
-                $user->obfs = Helpers::getDefaultObfs();
-                $user->usage = 1;
-                $user->transfer_enable = 1; // 新创建的账号给1,防止定时任务执行时发现u + d >= transfer_enable被判为流量超限而封禁
-                $user->enable_time = date('Y-m-d');
-                $user->expire_time = date('Y-m-d', strtotime("+" . $payment->order->goods->days . " days"));
-                $user->reg_ip = getClientIp();
-                $user->referral_uid = 0;
-                $user->traffic_reset_day = 0;
-                $user->status = 1;
-                $user->save();
-
-                if ($user->id) {
-                    Order::query()->where('oid', $payment->oid)->update(['user_id' => $user->id]);
-                }
-            }
-
-            // 更新支付单
-            $payment->pay_way = $msg['full_order_info']['order_info']['pay_type_str'] == 'WEIXIN_DAIXIAO' ? 1 : 2; // 1-微信、2-支付宝
-            $payment->status = 1;
-            $payment->save();
-
-            // 更新订单
-            $order = Order::query()->with(['user'])->where('oid', $payment->oid)->first();
-            $order->status = 2;
-            $order->save();
-
-            $goods = Goods::query()->where('id', $order->goods_id)->first();
-
-            // 商品为流量或者套餐
-            if ($goods->type <= 2) {
-                // 如果买的是套餐,则先将之前购买的所有套餐置都无效,并扣掉之前所有套餐的流量,重置用户已用流量为0
-                if ($goods->type == 2) {
-                    $existOrderList = Order::query()
-                        ->with(['goods'])
-                        ->whereHas('goods', function ($q) {
-                            $q->where('type', 2);
-                        })
-                        ->where('user_id', $order->user_id)
-                        ->where('oid', '<>', $order->oid)
-                        ->where('is_expire', 0)
-                        ->where('status', 2)
-                        ->get();
-
-                    foreach ($existOrderList as $vo) {
-                        Order::query()->where('oid', $vo->oid)->update(['is_expire' => 1]);
-
-                        // 先判断,防止手动扣减过流量的用户流量被扣成负数
-                        if ($order->user->transfer_enable - $vo->goods->traffic * 1048576 <= 0) {
-                            // 写入用户流量变动记录
-                            Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, 0, 0, '[在线支付]用户购买套餐,先扣减之前套餐的流量(扣完)');
-
-                            User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
-                        } else {
-                            // 写入用户流量变动记录
-                            $user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
-                            Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable - $vo->goods->traffic * 1048576), '[在线支付]用户购买套餐,先扣减之前套餐的流量(未扣完)');
-
-                            User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0]);
-                            User::query()->where('id', $order->user_id)->decrement('transfer_enable', $vo->goods->traffic * 1048576);
-                        }
-                    }
-                }
-
-                // 写入用户流量变动记录
-                $user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
-                Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable + $goods->traffic * 1048576), '[在线支付]用户购买商品,加上流量');
-
-                // 计算账号过期时间
-                if ($order->user->expire_time < date('Y-m-d', strtotime("+" . $goods->days . " days"))) {
-                    $expireTime = date('Y-m-d', strtotime("+" . $goods->days . " days"));
-                } else {
-                    $expireTime = $order->user->expire_time;
-                }
-
-                // 把商品的流量加到账号上
-                User::query()->where('id', $order->user_id)->increment('transfer_enable', $goods->traffic * 1048576);
-
-                // 套餐就改流量重置日,流量包不改
-                if ($goods->type == 2) {
-                    if (date('m') == 2 && date('d') == 29) {
-                        $traffic_reset_day = 28;
-                    } else {
-                        $traffic_reset_day = date('d') == 31 ? 30 : abs(date('d'));
-                    }
-                    User::query()->where('id', $order->user_id)->update(['traffic_reset_day' => $traffic_reset_day, 'expire_time' => $expireTime, 'enable' => 1]);
-                } else {
-                    User::query()->where('id', $order->user_id)->update(['expire_time' => $expireTime, 'enable' => 1]);
-                }
-
-                // 写入用户标签
-                if ($goods->label) {
-                    // 用户默认标签
-                    $defaultLabels = [];
-                    if (self::$systemConfig['initial_labels_for_user']) {
-                        $defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
-                    }
-
-                    // 取出现有的标签
-                    $userLabels = UserLabel::query()->where('user_id', $order->user_id)->pluck('label_id')->toArray();
-                    $goodsLabels = GoodsLabel::query()->where('goods_id', $order->goods_id)->pluck('label_id')->toArray();
-
-                    // 标签去重
-                    $newUserLabels = array_values(array_unique(array_merge($userLabels, $goodsLabels, $defaultLabels)));
-
-                    // 删除用户所有标签
-                    UserLabel::query()->where('user_id', $order->user_id)->delete();
-
-                    // 生成标签
-                    foreach ($newUserLabels as $vo) {
-                        $obj = new UserLabel();
-                        $obj->user_id = $order->user_id;
-                        $obj->label_id = $vo;
-                        $obj->save();
-                    }
-                }
-
-                // 写入返利日志
-                if ($order->user->referral_uid) {
-                    $this->addReferralLog($order->user_id, $order->user->referral_uid, $order->oid, $order->amount, $order->amount * self::$systemConfig['referral_percent']);
-                }
-
-                // 取消重复返利
-                User::query()->where('id', $order->user_id)->update(['referral_uid' => 0]);
-            } elseif ($goods->type == 3) { // 商品为在线充值
-                User::query()->where('id', $order->user_id)->increment('balance', $goods->price * 100);
-
-                // 余额变动记录日志
-                $this->addUserBalanceLog($order->user_id, $order->oid, $order->user->balance, $order->user->balance + $goods->price, $goods->price, '用户在线充值');
-            }
-
-            // 自动提号机:如果order的email值不为空
-            if ($order->email) {
-                $title = '自动发送账号信息';
-                $content = [
-                    'order_sn'      => $order->order_sn,
-                    'goods_name'    => $order->goods->name,
-                    'goods_traffic' => flowAutoShow($order->goods->traffic * 1048576),
-                    'port'          => $order->user->port,
-                    'passwd'        => $order->user->passwd,
-                    'method'        => $order->user->method,
-                    //'protocol'       => $order->user->protocol,
-                    //'protocol_param' => $order->user->protocol_param,
-                    //'obfs'           => $order->user->obfs,
-                    //'obfs_param'     => $order->user->obfs_param,
-                    'created_at'    => $order->created_at->toDateTimeString(),
-                    'expire_at'     => $order->expire_at
-                ];
-
-                // 获取可用节点列表
-                $labels = UserLabel::query()->where('user_id', $order->user_id)->get()->pluck('label_id');
-                $nodeIds = SsNodeLabel::query()->whereIn('label_id', $labels)->get()->pluck('node_id');
-                $nodeList = SsNode::query()->whereIn('id', $nodeIds)->orderBy('sort', 'desc')->orderBy('id', 'desc')->get()->toArray();
-                $content['serverList'] = $nodeList;
-
-                $logId = Helpers::addEmailLog($order->email, $title, json_encode($content));
-                Mail::to($order->email)->send(new sendUserInfo($logId, $content));
-            }
-
-            DB::commit();
-        } catch (\Exception $e) {
-            DB::rollBack();
-
-            Log::info('【有赞云】回调更新支付单和订单异常:' . $e->getMessage());
-        }
-
-        exit();
-    }
-
-    // 创建交易
-    private function tradeCreate($msg)
-    {
-        Log::info('【有赞云】回调创建交易');
-        exit();
-    }
-
-    // 关闭交易(无视,系统自带15分钟自动关闭未支付订单的定时任务)
-    private function tradeClose($msg)
-    {
-        Log::info('【有赞云】回调关闭交易');
-
-        exit();
-    }
-
-    // 交易成功
-    private function tradeSuccess($msg)
-    {
-        Log::info('【有赞云】回调交易成功');
-
-        exit();
-    }
-
-    // 卖家部分发货
-    private function tradePartlySellerShip($msg)
-    {
-        Log::info('【有赞云】回调卖家部分发货');
-        exit();
-    }
-
-    // 卖家发货
-    private function tradeSellerShip($msg)
-    {
-        Log::info('【有赞云】回调卖家发货');
-        exit();
-    }
-
-    // 买家付款
-    private function tradeBuyerPay($msg)
-    {
-        Log::info('【有赞云】回调买家付款');
-        exit();
-    }
-
-    // 卖家修改交易备注
-    private function tradeMemoModified($msg)
-    {
-        Log::info('【有赞云】回调卖家修改交易备注');
-        exit();
-    }
-
-    public function show(Request $request)
-    {
-        exit('show');
-    }
-
-    // 写入回调请求日志
-    private function callbackLog($client_id, $yz_id, $kdt_id, $kdt_name, $mode, $msg, $sendCount, $sign, $status, $test, $type, $version)
-    {
-        $obj = new PaymentCallback();
-        $obj->client_id = $client_id;
-        $obj->yz_id = $yz_id;
-        $obj->kdt_id = $kdt_id;
-        $obj->kdt_name = $kdt_name;
-        $obj->mode = $mode;
-        $obj->msg = urldecode($msg);
-        $obj->sendCount = $sendCount;
-        $obj->sign = $sign;
-        $obj->status = $status;
-        $obj->test = $test;
-        $obj->type = $type;
-        $obj->version = $version;
-        $obj->save();
-
-        return $obj->id;
-    }
+	protected static $systemConfig;
+
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	// 接收GET请求
+	public function index(Request $request)
+	{
+		Log::info("【有赞云】回调接口[GET]:".var_export($request->all(), TRUE).'['.getClientIp().']');
+		exit("【有赞云】接口正常");
+	}
+
+	// 接收POST请求
+	public function store(Request $request)
+	{
+		Log::info("【有赞云】回调接口[POST]:".var_export($request->all(), TRUE));
+
+		$json = file_get_contents('php://input');
+		$data = json_decode($json, TRUE);
+		if(!$data){
+			Log::info('YZY-POST:回调数据无法解析,可能是非法请求['.getClientIp().']');
+			exit();
+		}
+
+		// 判断消息是否合法
+		$msg = $data['msg'];
+		$sign_string = self::$systemConfig['youzan_client_id']."".$msg."".self::$systemConfig['youzan_client_secret'];
+		$sign = md5($sign_string);
+		if($sign != $data['sign']){
+			Log::info('本地签名:'.$sign_string.' | 远程签名:'.$data['sign']);
+			Log::info('YZY-POST:回调数据签名错误,可能是非法请求['.getClientIp().']');
+			exit();
+		}else{
+			// 返回请求成功标识给有赞
+			var_dump(["code" => 0, "msg" => "success"]);
+		}
+
+		// 容错
+		if(!isset($data['kdt_name'])){
+			Log::info("【有赞云】回调数据解析错误,请检查有赞支付设置是否与有赞控制台中的信息保持一致。如果还出现此提示,请执行一遍php artisan cache:clear命令");
+			exit();
+		}
+
+		// 先写入回调日志
+		$this->callbackLog($data['client_id'], $data['id'], $data['kdt_id'], $data['kdt_name'], $data['mode'], $data['msg'], $data['sendCount'], $data['sign'], $data['status'], $data['test'], $data['type'], $data['version']);
+
+		// msg内容经过 urlencode 编码,进行解码
+		$msg = json_decode(urldecode($msg), TRUE);
+
+		switch($data['type']){
+			case 'trade_TradePaid':
+				$this->tradePaid($msg);
+				break;
+			case 'trade_TradeCreate':
+				$this->tradeCreate($msg);
+				break;
+			case 'trade_TradeClose':
+				$this->tradeClose($msg);
+				break;
+			case 'trade_TradeSuccess':
+				$this->tradeSuccess($msg);
+				break;
+			case 'trade_TradePartlySellerShip':
+				$this->tradePartlySellerShip($msg);
+				break;
+			case 'trade_TradeSellerShip':
+				$this->tradeSellerShip($msg);
+				break;
+			case 'trade_TradeBuyerPay':
+				$this->tradeBuyerPay($msg);
+				break;
+			case 'trade_TradeMemoModified':
+				$this->tradeMemoModified($msg);
+				break;
+			default:
+				Log::info('【有赞云】回调无法识别,可能是没有启用[交易消息V3]接口,请到有赞云控制台启用消息推送服务');
+				exit();
+		}
+
+		exit();
+	}
+
+	// 交易支付
+	private function tradePaid($msg)
+	{
+		Log::info('【有赞云】回调交易支付');
+
+		$payment = Payment::query()->with(['order', 'order.goods'])->where('qr_id', $msg['qr_info']['qr_id'])->first();
+		if(!$payment){
+			Log::info('【有赞云】回调订单不存在');
+			exit();
+		}
+
+		if($payment->status != '0'){
+			Log::info('【有赞云】回调订单状态不正确');
+			exit();
+		}
+
+		// 处理订单
+		DB::beginTransaction();
+		try{
+			// 如果支付单中没有用户信息则创建一个用户
+			if(!$payment->user_id){
+				// 生成一个可用端口
+				$port = self::$systemConfig['is_rand_port']? Helpers::getRandPort() : Helpers::getOnlyPort();
+
+				$user = new User();
+				$user->username = '自动生成-'.$payment->order->email;
+				$user->password = Hash::make(makeRandStr());
+				$user->port = $port;
+				$user->passwd = makeRandStr();
+				$user->vmess_id = createGuid();
+				$user->enable = 1;
+				$user->method = Helpers::getDefaultMethod();
+				$user->protocol = Helpers::getDefaultProtocol();
+				$user->obfs = Helpers::getDefaultObfs();
+				$user->usage = 1;
+				$user->transfer_enable = 1; // 新创建的账号给1,防止定时任务执行时发现u + d >= transfer_enable被判为流量超限而封禁
+				$user->enable_time = date('Y-m-d');
+				$user->expire_time = date('Y-m-d', strtotime("+".$payment->order->goods->days." days"));
+				$user->reg_ip = getClientIp();
+				$user->referral_uid = 0;
+				$user->traffic_reset_day = 0;
+				$user->status = 1;
+				$user->save();
+
+				if($user->id){
+					Order::query()->where('oid', $payment->oid)->update(['user_id' => $user->id]);
+				}
+			}
+
+			// 更新支付单
+			$payment->pay_way = $msg['full_order_info']['order_info']['pay_type_str'] == 'WEIXIN_DAIXIAO'? 1 : 2; // 1-微信、2-支付宝
+			$payment->status = 1;
+			$payment->save();
+
+			// 更新订单
+			$order = Order::query()->with(['user'])->where('oid', $payment->oid)->first();
+			$order->status = 2;
+			$order->save();
+
+			$goods = Goods::query()->where('id', $order->goods_id)->first();
+
+			// 商品为流量或者套餐
+			if($goods->type <= 2){
+				// 如果买的是套餐,则先将之前购买的所有套餐置都无效,并扣掉之前所有套餐的流量,重置用户已用流量为0
+				if($goods->type == 2){
+					$existOrderList = Order::query()
+						->with(['goods'])
+						->whereHas('goods', function($q){
+							$q->where('type', 2);
+						})
+						->where('user_id', $order->user_id)
+						->where('oid', '<>', $order->oid)
+						->where('is_expire', 0)
+						->where('status', 2)
+						->get();
+
+					foreach($existOrderList as $vo){
+						Order::query()->where('oid', $vo->oid)->update(['is_expire' => 1]);
+
+						// 先判断,防止手动扣减过流量的用户流量被扣成负数
+						if($order->user->transfer_enable-$vo->goods->traffic*1048576 <= 0){
+							// 写入用户流量变动记录
+							Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, 0, 0, '[在线支付]用户购买套餐,先扣减之前套餐的流量(扣完)');
+
+							User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
+						}else{
+							// 写入用户流量变动记录
+							$user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
+							Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable-$vo->goods->traffic*1048576), '[在线支付]用户购买套餐,先扣减之前套餐的流量(未扣完)');
+
+							User::query()->where('id', $order->user_id)->update(['u' => 0, 'd' => 0]);
+							User::query()->where('id', $order->user_id)->decrement('transfer_enable', $vo->goods->traffic*1048576);
+						}
+					}
+				}
+
+				// 写入用户流量变动记录
+				$user = User::query()->where('id', $order->user_id)->first(); // 重新取出user信息
+				Helpers::addUserTrafficModifyLog($order->user_id, $order->oid, $user->transfer_enable, ($user->transfer_enable+$goods->traffic*1048576), '[在线支付]用户购买商品,加上流量');
+
+				// 计算账号过期时间
+				if($order->user->expire_time < date('Y-m-d', strtotime("+".$goods->days." days"))){
+					$expireTime = date('Y-m-d', strtotime("+".$goods->days." days"));
+				}else{
+					$expireTime = $order->user->expire_time;
+				}
+
+				// 把商品的流量加到账号上
+				User::query()->where('id', $order->user_id)->increment('transfer_enable', $goods->traffic*1048576);
+
+				// 套餐就改流量重置日,流量包不改
+				if($goods->type == 2){
+					if(date('m') == 2 && date('d') == 29){
+						$traffic_reset_day = 28;
+					}else{
+						$traffic_reset_day = date('d') == 31? 30 : abs(date('d'));
+					}
+					User::query()->where('id', $order->user_id)->update(['traffic_reset_day' => $traffic_reset_day, 'expire_time' => $expireTime, 'enable' => 1]);
+				}else{
+					User::query()->where('id', $order->user_id)->update(['expire_time' => $expireTime, 'enable' => 1]);
+				}
+
+				// 写入用户标签
+				if($goods->label){
+					// 用户默认标签
+					$defaultLabels = [];
+					if(self::$systemConfig['initial_labels_for_user']){
+						$defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
+					}
+
+					// 取出现有的标签
+					$userLabels = UserLabel::query()->where('user_id', $order->user_id)->pluck('label_id')->toArray();
+					$goodsLabels = GoodsLabel::query()->where('goods_id', $order->goods_id)->pluck('label_id')->toArray();
+
+					// 标签去重
+					$newUserLabels = array_values(array_unique(array_merge($userLabels, $goodsLabels, $defaultLabels)));
+
+					// 删除用户所有标签
+					UserLabel::query()->where('user_id', $order->user_id)->delete();
+
+					// 生成标签
+					foreach($newUserLabels as $vo){
+						$obj = new UserLabel();
+						$obj->user_id = $order->user_id;
+						$obj->label_id = $vo;
+						$obj->save();
+					}
+				}
+
+				// 写入返利日志
+				if($order->user->referral_uid){
+					$this->addReferralLog($order->user_id, $order->user->referral_uid, $order->oid, $order->amount, $order->amount*self::$systemConfig['referral_percent']);
+				}
+
+				// 取消重复返利
+				User::query()->where('id', $order->user_id)->update(['referral_uid' => 0]);
+			}elseif($goods->type == 3){ // 商品为在线充值
+				User::query()->where('id', $order->user_id)->increment('balance', $goods->price*100);
+
+				// 余额变动记录日志
+				$this->addUserBalanceLog($order->user_id, $order->oid, $order->user->balance, $order->user->balance+$goods->price, $goods->price, '用户在线充值');
+			}
+
+			// 自动提号机:如果order的email值不为空
+			if($order->email){
+				$title = '自动发送账号信息';
+				$content = [
+					'order_sn'      => $order->order_sn,
+					'goods_name'    => $order->goods->name,
+					'goods_traffic' => flowAutoShow($order->goods->traffic*1048576),
+					'port'          => $order->user->port,
+					'passwd'        => $order->user->passwd,
+					'method'        => $order->user->method,
+					//'protocol'       => $order->user->protocol,
+					//'protocol_param' => $order->user->protocol_param,
+					//'obfs'           => $order->user->obfs,
+					//'obfs_param'     => $order->user->obfs_param,
+					'created_at'    => $order->created_at->toDateTimeString(),
+					'expire_at'     => $order->expire_at
+				];
+
+				// 获取可用节点列表
+				$labels = UserLabel::query()->where('user_id', $order->user_id)->get()->pluck('label_id');
+				$nodeIds = SsNodeLabel::query()->whereIn('label_id', $labels)->get()->pluck('node_id');
+				$nodeList = SsNode::query()->whereIn('id', $nodeIds)->orderBy('sort', 'desc')->orderBy('id', 'desc')->get()->toArray();
+				$content['serverList'] = $nodeList;
+
+				$logId = Helpers::addEmailLog($order->email, $title, json_encode($content));
+				Mail::to($order->email)->send(new sendUserInfo($logId, $content));
+			}
+
+			DB::commit();
+		} catch(Exception $e){
+			DB::rollBack();
+
+			Log::info('【有赞云】回调更新支付单和订单异常:'.$e->getMessage());
+		}
+
+		exit();
+	}
+
+	// 创建交易
+	private function tradeCreate($msg)
+	{
+		Log::info('【有赞云】回调创建交易');
+		exit();
+	}
+
+	// 关闭交易(无视,系统自带15分钟自动关闭未支付订单的定时任务)
+	private function tradeClose($msg)
+	{
+		Log::info('【有赞云】回调关闭交易');
+
+		exit();
+	}
+
+	// 交易成功
+	private function tradeSuccess($msg)
+	{
+		Log::info('【有赞云】回调交易成功');
+
+		exit();
+	}
+
+	// 卖家部分发货
+	private function tradePartlySellerShip($msg)
+	{
+		Log::info('【有赞云】回调卖家部分发货');
+		exit();
+	}
+
+	// 卖家发货
+	private function tradeSellerShip($msg)
+	{
+		Log::info('【有赞云】回调卖家发货');
+		exit();
+	}
+
+	// 买家付款
+	private function tradeBuyerPay($msg)
+	{
+		Log::info('【有赞云】回调买家付款');
+		exit();
+	}
+
+	// 卖家修改交易备注
+	private function tradeMemoModified($msg)
+	{
+		Log::info('【有赞云】回调卖家修改交易备注');
+		exit();
+	}
+
+	public function show(Request $request)
+	{
+		exit('show');
+	}
+
+	// 写入回调请求日志
+	private function callbackLog($client_id, $yz_id, $kdt_id, $kdt_name, $mode, $msg, $sendCount, $sign, $status, $test, $type, $version)
+	{
+		$obj = new PaymentCallback();
+		$obj->client_id = $client_id;
+		$obj->yz_id = $yz_id;
+		$obj->kdt_id = $kdt_id;
+		$obj->kdt_name = $kdt_name;
+		$obj->mode = $mode;
+		$obj->msg = urldecode($msg);
+		$obj->sendCount = $sendCount;
+		$obj->sign = $sign;
+		$obj->status = $status;
+		$obj->test = $test;
+		$obj->type = $type;
+		$obj->version = $version;
+		$obj->save();
+
+		return $obj->id;
+	}
 }

+ 727 - 727
app/Http/Controllers/AuthController.php

@@ -5,7 +5,6 @@ namespace App\Http\Controllers;
 use App\Components\Helpers;
 use App\Components\IPIP;
 use App\Components\QQWry;
-use App\Components\CaptchaVerify;
 use App\Http\Models\Invite;
 use App\Http\Models\User;
 use App\Http\Models\UserLabel;
@@ -19,6 +18,7 @@ use App\Mail\sendVerifyCode;
 use Auth;
 use Cache;
 use Captcha;
+use Cookie;
 use Hash;
 use Illuminate\Http\Request;
 use Log;
@@ -37,730 +37,730 @@ use Validator;
  */
 class AuthController extends Controller
 {
-    protected static $systemConfig;
-
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    // 登录
-    public function login(Request $request)
-    {
-        if ($request->isMethod('POST')) {
-            $this->validate($request, [
-                'username' => 'required',
-                'password' => 'required'
-            ], [
-                'username.required' => trans('auth.email_null'),
-                'password.required' => trans('auth.password_null')
-            ]);
-
-            // 是否校验验证码
-            switch (self::$systemConfig['is_captcha']) {
-                case 1: // 默认图形验证码
-                    if (!Captcha::check($request->captcha)) {
-                        return Redirect::back()->withInput()->withErrors(trans('auth.captcha_error'));
-                    }
-                    break;
-                case 2: // Geetest
-                    $result = $this->validate($request, [
-                        'geetest_challenge' => 'required|geetest'
-                    ], [
-                        'geetest' => trans('auth.captcha_fail')
-                    ]);
-
-                    if (!$result) {
-                        return Redirect::back()->withInput()->withErrors(trans('auth.fail_captcha'));
-                    }
-                    break;
-                case 3: // Google reCAPTCHA
-                    $result = $this->validate($request, [
-                        'g-recaptcha-response' => 'required|NoCaptcha'
-                    ]);
-
-                    if (!$result) {
-                        return Redirect::back()->withInput()->withErrors(trans('auth.fail_captcha'));
-                    }
-                    break;
-                default: // 不启用验证码
-                    break;
-            }
-
-            // 验证账号并创建会话
-            if (!Auth::attempt(['username' => $request->username, 'password' => $request->password], $request->remember)) {
-                return Redirect::back()->withInput()->withErrors(trans('auth.login_error'));
-            }
-
-            // 校验普通用户账号状态
-            if (!Auth::user()->is_admin) {
-                if (Auth::user()->status < 0) {
-                    Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
-
-                    return Redirect::back()->withInput()->withErrors(trans('auth.login_ban', ['email' => self::$systemConfig['admin_email']]));
-                }
-
-                if (Auth::user()->status == 0 && self::$systemConfig['is_active_register']) {
-                    Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
-
-                    return Redirect::back()->withInput()->withErrors(trans('auth.active_tip') . '<a href="/activeUser?username=' . $request->username . '" target="_blank"><span style="color:#000">【' . trans('auth.active_account') . '】</span></a>');
-                }
-            }
-
-            // 写入登录日志
-            $this->addUserLoginLog(Auth::user()->id, getClientIp());
-
-            // 更新登录信息
-            User::uid()->update(['last_login' => time()]);
-
-            // 根据权限跳转
-            if (Auth::user()->is_admin) {
-                return Redirect::to('admin');
-            }
-
-            return Redirect::to('/');
-        } else {
-            if (Auth::check()) {
-                if (Auth::user()->is_admin) {
-                    return Redirect::to('admin');
-                }
-
-                return Redirect::to('/');
-            }
-
-            return Response::view('auth.login');
-        }
-    }
-
-    // 退出
-    public function logout(Request $request)
-    {
-        Auth::logout();
-
-        return Redirect::to('login');
-    }
-
-    // 注册
-    public function register(Request $request)
-    {
-        $cacheKey = 'register_times_' . md5(getClientIp()); // 注册限制缓存key
-
-        if ($request->isMethod('POST')) {
-            $this->validate($request, [
-                'username'   => 'required|email|unique:user',
-                'password'   => 'required|min:6',
-                'repassword' => 'required|same:password',
-            ], [
-                'username.required'   => trans('auth.email_null'),
-                'username.email'      => trans('auth.email_legitimate'),
-                'username.unique'     => trans('auth.email_exist'),
-                'password.required'   => trans('auth.password_null'),
-                'password.min'        => trans('auth.password_limit'),
-                'repassword.required' => trans('auth.retype_password'),
-                'repassword.same'     => trans('auth.password_same')
-            ]);
-
-            // 防止重复提交
-            if ($request->register_token != Session::get('register_token')) {
-                return Redirect::back()->withInput()->withErrors(trans('auth.repeat_request'));
-            } else {
-                Session::forget('register_token');
-            }
-
-            // 是否开启注册
-            if (!self::$systemConfig['is_register']) {
-                return Redirect::back()->withErrors(trans('auth.register_close'));
-            }
-
-            // 校验域名邮箱是否在敏感词中
-            $sensitiveWords = $this->sensitiveWords();
-            $usernameSuffix = explode('@', $request->username); // 提取邮箱后缀
-            if (in_array(strtolower($usernameSuffix[1]), $sensitiveWords)) {
-                return Redirect::back()->withInput()->withErrors(trans('auth.email_banned'));
-            }
-
-            // 如果需要邀请注册
-            if (self::$systemConfig['is_invite_register']) {
-                // 必须使用邀请码
-                if (self::$systemConfig['is_invite_register'] == 2 && !$request->code) {
-                    return Redirect::back()->withInput()->withErrors(trans('auth.code_null'));
-                }
-
-                // 校验邀请码合法性
-                if ($request->code) {
-                    $codeEnable = Invite::query()->where('code', $request->code)->where('status', 0)->first();
-                    if (!$codeEnable) {
-                        return Redirect::back()->withInput($request->except(['code']))->withErrors(trans('auth.code_error'));
-                    }
-                }
-            }
-
-            // 如果开启注册发送验证码
-            if (self::$systemConfig['is_verify_register']) {
-                if (!$request->verify_code) {
-                    return Redirect::back()->withInput($request->except(['verify_code']))->withErrors(trans('auth.captcha_null'));
-                } else {
-                    $verifyCode = VerifyCode::query()->where('username', $request->username)->where('code', $request->verify_code)->where('status', 0)->first();
-                    if (!$verifyCode) {
-                        return Redirect::back()->withInput($request->except(['verify_code']))->withErrors(trans('auth.captcha_overtime'));
-                    }
-
-                    $verifyCode->status = 1;
-                    $verifyCode->save();
-                }
-            } elseif (self::$systemConfig['is_captcha']) { // 是否校验验证码
-                switch (self::$systemConfig['is_captcha']) {
-                    case 1: // 默认图形验证码
-                        if (!Captcha::check($request->captcha)) {
-                            return Redirect::back()->withInput()->withErrors(trans('auth.captcha_error'));
-                        }
-                        break;
-                    case 2: // Geetest
-                        $result = $this->validate($request, [
-                            'geetest_challenge' => 'required|geetest'
-                        ], [
-                            'geetest' => trans('auth.captcha_fail')
-                        ]);
-
-                        if (!$result) {
-                            return Redirect::back()->withInput()->withErrors(trans('auth.captcha_fail'));
-                        }
-                        break;
-                    case 3: // Google reCAPTCHA
-                        $result = $this->validate($request, [
-                            'g-recaptcha-response' => 'required|NoCaptcha'
-                        ]);
-
-                        if (!$result) {
-                            return Redirect::back()->withInput()->withErrors(trans('auth.captcha_fail'));
-                        }
-                        break;
-                    default: // 不启用验证码
-                        break;
-                }
-            }
-
-            // 24小时内同IP注册限制
-            if (self::$systemConfig['register_ip_limit']) {
-                if (Cache::has($cacheKey)) {
-                    $registerTimes = Cache::get($cacheKey);
-                    if ($registerTimes >= self::$systemConfig['register_ip_limit']) {
-                        return Redirect::back()->withInput($request->except(['code']))->withErrors(trans('auth.register_anti'));
-                    }
-                }
-            }
-
-            // 获取可用端口
-            $port = self::$systemConfig['is_rand_port'] ? Helpers::getRandPort() : Helpers::getOnlyPort();
-            if ($port > self::$systemConfig['max_port']) {
-                return Redirect::back()->withInput()->withErrors(trans('auth.register_close'));
-            }
-
-            // 获取aff
-            $affArr = $this->getAff($request->code, intval($request->aff));
-            $referral_uid = $affArr['referral_uid'];
-
-            $transfer_enable = $referral_uid ? (self::$systemConfig['default_traffic'] + self::$systemConfig['referral_traffic']) * 1048576 : self::$systemConfig['default_traffic'] * 1048576;
-
-            // 创建新用户
-            $user = new User();
-            $user->username = $request->username;
-            $user->password = Hash::make($request->password);
-            $user->port = $port;
-            $user->passwd = makeRandStr();
-            $user->vmess_id = createGuid();
-            $user->transfer_enable = $transfer_enable;
-            $user->method = Helpers::getDefaultMethod();
-            $user->protocol = Helpers::getDefaultProtocol();
-            $user->obfs = Helpers::getDefaultObfs();
-            $user->enable_time = date('Y-m-d H:i:s');
-            $user->expire_time = date('Y-m-d H:i:s', strtotime("+" . self::$systemConfig['default_days'] . " days"));
-            $user->reg_ip = getClientIp();
-            $user->referral_uid = $referral_uid;
-            $user->save();
-
-            // 注册失败,抛出异常
-            if (!$user->id) {
-                return Redirect::back()->withInput()->withErrors(trans('auth.register_fail'));
-            }
-
-            // 生成订阅码
-            $subscribe = new UserSubscribe();
-            $subscribe->user_id = $user->id;
-            $subscribe->code = Helpers::makeSubscribeCode();
-            $subscribe->times = 0;
-            $subscribe->save();
-
-            // 注册次数+1
-            if (Cache::has($cacheKey)) {
-                Cache::increment($cacheKey);
-            } else {
-                Cache::put($cacheKey, 1, 1440); // 24小时
-            }
-
-            // 初始化默认标签
-            if (strlen(self::$systemConfig['initial_labels_for_user'])) {
-                $labels = explode(',', self::$systemConfig['initial_labels_for_user']);
-                foreach ($labels as $label) {
-                    $userLabel = new UserLabel();
-                    $userLabel->user_id = $user->id;
-                    $userLabel->label_id = $label;
-                    $userLabel->save();
-                }
-            }
-
-            // 更新邀请码
-            if (self::$systemConfig['is_invite_register'] && $affArr['code_id']) {
-                Invite::query()->where('id', $affArr['code_id'])->update(['fuid' => $user->id, 'status' => 1]);
-            }
-
-            // 清除邀请人Cookie
-            \Cookie::unqueue('register_aff');
-
-            if (self::$systemConfig['is_verify_register']) {
-                if ($referral_uid) {
-                    $transfer_enable = self::$systemConfig['referral_traffic'] * 1048576;
-
-                    User::query()->where('id', $referral_uid)->increment('transfer_enable', $transfer_enable);
-                    User::query()->where('id', $referral_uid)->update(['status' => 1, 'enable' => 1]);
-                }
-
-                User::query()->where('id', $user->id)->update(['status' => 1, 'enable' => 1]);
-
-                Session::flash('regSuccessMsg', trans('auth.register_success'));
-            } else {
-                // 发送激活邮件
-                if (self::$systemConfig['is_active_register']) {
-                    // 生成激活账号的地址
-                    $token = md5(self::$systemConfig['website_name'] . $request->username . microtime());
-                    $activeUserUrl = self::$systemConfig['website_url'] . '/active/' . $token;
-                    $this->addVerify($user->id, $token);
-
-                    $logId = Helpers::addEmailLog($request->username, '注册激活', '请求地址:' . $activeUserUrl);
-                    Mail::to($request->username)->send(new activeUser($logId, $activeUserUrl));
-
-                    Session::flash('regSuccessMsg', trans('auth.register_success_tip'));
-                } else {
-                    // 如果不需要激活,则直接给推荐人加流量
-                    if ($referral_uid) {
-                        $transfer_enable = self::$systemConfig['referral_traffic'] * 1048576;
-
-                        User::query()->where('id', $referral_uid)->increment('transfer_enable', $transfer_enable);
-                        User::query()->where('id', $referral_uid)->update(['status' => 1, 'enable' => 1]);
-                    }
-
-                    User::query()->where('id', $user->id)->update(['status' => 1, 'enable' => 1]);
-
-                    Session::flash('regSuccessMsg', trans('auth.register_success'));
-                }
-            }
-
-            return Redirect::to('login')->withInput();
-        } else {
-            Session::put('register_token', makeRandStr(16));
-
-            return Response::view('auth.register');
-        }
-    }
-
-    // 重设密码页
-    public function resetPassword(Request $request)
-    {
-        if ($request->isMethod('POST')) {
-            // 校验请求
-            $this->validate($request, [
-                'username' => 'required|email'
-            ], [
-                'username.required' => trans('auth.email_null'),
-                'username.email'    => trans('auth.email_legitimate')
-            ]);
-
-            // 是否开启重设密码
-            if (!self::$systemConfig['is_reset_password']) {
-                return Redirect::back()->withErrors(trans('auth.reset_password_close', ['email' => self::$systemConfig['admin_email']]));
-            }
-
-            // 查找账号
-            $user = User::query()->where('username', $request->username)->first();
-            if (!$user) {
-                return Redirect::back()->withErrors(trans('auth.email_notExist'));
-            }
-
-            // 24小时内重设密码次数限制
-            $resetTimes = 0;
-            if (Cache::has('resetPassword_' . md5($request->username))) {
-                $resetTimes = Cache::get('resetPassword_' . md5($request->username));
-                if ($resetTimes >= self::$systemConfig['reset_password_times']) {
-                    return Redirect::back()->withErrors(trans('auth.reset_password_limit', ['time' => self::$systemConfig['reset_password_times']]));
-                }
-            }
-
-            // 生成取回密码的地址
-            $token = md5(self::$systemConfig['website_name'] . $request->username . microtime());
-            $verify = new Verify();
-            $verify->type = 1;
-            $verify->user_id = $user->id;
-            $verify->token = $token;
-            $verify->status = 0;
-            $verify->save();
-
-            // 发送邮件
-            $resetPasswordUrl = self::$systemConfig['website_url'] . '/reset/' . $token;
-
-            $logId = Helpers::addEmailLog($request->username, '重置密码', '请求地址:' . $resetPasswordUrl);
-            Mail::to($request->username)->send(new resetPassword($logId, $resetPasswordUrl));
-
-            Cache::put('resetPassword_' . md5($request->username), $resetTimes + 1, 1440);
-
-            return Redirect::back()->with('successMsg', trans('auth.reset_password_success_tip'));
-        } else {
-            return Response::view('auth.resetPassword');
-        }
-    }
-
-    // 重设密码
-    public function reset(Request $request, $token)
-    {
-        if (!$token) {
-            return Redirect::to('login');
-        }
-
-        if ($request->isMethod('POST')) {
-            $this->validate($request, [
-                'password'   => 'required|min:6',
-                'repassword' => 'required|same:password'
-            ], [
-                'password.required'   => trans('auth.password_null'),
-                'password.min'        => trans('auth.password_limit'),
-                'repassword.required' => trans('auth.password_null'),
-                'repassword.min'      => trans('auth.password_limit'),
-                'repassword.same'     => trans('auth.password_same'),
-            ]);
-
-            // 校验账号
-            $verify = Verify::type(1)->with('user')->where('token', $token)->first();
-            if (!$verify) {
-                return Redirect::to('login');
-            } elseif ($verify->status == 1) {
-                return Redirect::back()->withErrors(trans('auth.overtime'));
-            } elseif ($verify->user->status < 0) {
-                return Redirect::back()->withErrors(trans('auth.email_banned'));
-            } elseif (Hash::check($request->password, $verify->user->password)) {
-                return Redirect::back()->withErrors(trans('auth.rest_password_same_fail'));
-            }
-
-            // 更新密码
-            $ret = User::query()->where('id', $verify->user_id)->update(['password' => Hash::make($request->password)]);
-            if (!$ret) {
-                return Redirect::back()->withErrors(trans('auth.rest_password_fail'));
-            }
-
-            // 置为已使用
-            $verify->status = 1;
-            $verify->save();
-
-            return Redirect::back()->with('successMsg', trans('auth.reset_password_new'));
-        } else {
-            $verify = Verify::type(1)->where('token', $token)->first();
-            if (!$verify) {
-                return Redirect::to('login');
-            } elseif (time() - strtotime($verify->created_at) >= 1800) {
-                // 置为已失效
-                $verify->status = 2;
-                $verify->save();
-            }
-
-            // 重新获取一遍verify
-            $view['verify'] = Verify::type(1)->where('token', $token)->first();
-
-            return Response::view('auth.reset', $view);
-        }
-    }
-
-    // 激活账号页
-    public function activeUser(Request $request)
-    {
-        if ($request->isMethod('POST')) {
-            $this->validate($request, [
-                'username' => 'required|email|exists:user,username'
-            ], [
-                'username.required' => trans('auth.email_null'),
-                'username.email'    => trans('auth.email_legitimate'),
-                'username.exists'   => trans('auth.email_notExist')
-            ]);
-
-            // 是否开启账号激活
-            if (!self::$systemConfig['is_active_register']) {
-                return Redirect::back()->withInput()->withErrors(trans('auth.active_close', ['email' => self::$systemConfig['admin_email']]));
-            }
-
-            // 查找账号
-            $user = User::query()->where('username', $request->username)->first();
-            if ($user->status < 0) {
-                return Redirect::back()->withErrors(trans('auth.login_ban', ['email' => self::$systemConfig['admin_email']]));
-            } elseif ($user->status > 0) {
-                return Redirect::back()->withErrors(trans('auth.email_normal'));
-            }
-
-            // 24小时内激活次数限制
-            $activeTimes = 0;
-            if (Cache::has('activeUser_' . md5($request->username))) {
-                $activeTimes = Cache::get('activeUser_' . md5($request->username));
-                if ($activeTimes >= self::$systemConfig['active_times']) {
-                    return Redirect::back()->withErrors(trans('auth.active_limit', ['time' => self::$systemConfig['admin_email']]));
-                }
-            }
-
-            // 生成激活账号的地址
-            $token = md5(self::$systemConfig['website_name'] . $request->username . microtime());
-            $verify = new Verify();
-            $verify->type = 1;
-            $verify->user_id = $user->id;
-            $verify->token = $token;
-            $verify->status = 0;
-            $verify->save();
-
-            // 发送邮件
-            $activeUserUrl = self::$systemConfig['website_url'] . '/active/' . $token;
-
-            $logId = Helpers::addEmailLog($request->username, '激活账号', '请求地址:' . $activeUserUrl);
-            Mail::to($request->username)->send(new activeUser($logId, $activeUserUrl));
-
-            Cache::put('activeUser_' . md5($request->username), $activeTimes + 1, 1440);
-
-            return Redirect::back()->with('successMsg', trans('auth.register_success_tip'));
-        } else {
-            return Response::view('auth.activeUser');
-        }
-    }
-
-    // 激活账号
-    public function active(Request $request, $token)
-    {
-        if (!$token) {
-            return Redirect::to('login');
-        }
-
-        $verify = Verify::type(1)->with('user')->where('token', $token)->first();
-        if (!$verify) {
-            return Redirect::to('login');
-        } elseif (empty($verify->user)) {
-            Session::flash('errorMsg', trans('auth.overtime'));
-
-            return Response::view('auth.active');
-        } elseif ($verify->status > 0) {
-            Session::flash('errorMsg', trans('auth.overtime'));
-
-            return Response::view('auth.active');
-        } elseif ($verify->user->status != 0) {
-            Session::flash('errorMsg', trans('auth.email_normal'));
-
-            return Response::view('auth.active');
-        } elseif (time() - strtotime($verify->created_at) >= 1800) {
-            Session::flash('errorMsg', trans('auth.overtime'));
-
-            // 置为已失效
-            $verify->status = 2;
-            $verify->save();
-
-            return Response::view('auth.active');
-        }
-
-        // 更新账号状态
-        $ret = User::query()->where('id', $verify->user_id)->update(['status' => 1]);
-        if (!$ret) {
-            Session::flash('errorMsg', trans('auth.active_fail'));
-
-            return Redirect::back();
-        }
-
-        // 置为已使用
-        $verify->status = 1;
-        $verify->save();
-
-        // 账号激活后给邀请人送流量
-        if ($verify->user->referral_uid) {
-            $transfer_enable = self::$systemConfig['referral_traffic'] * 1048576;
-
-            User::query()->where('id', $verify->user->referral_uid)->increment('transfer_enable', $transfer_enable);
-            User::query()->where('id', $verify->user->referral_uid)->update(['enable' => 1]);
-        }
-
-        Session::flash('successMsg', trans('auth.active_success'));
-
-        return Response::view('auth.active');
-    }
-
-    // 发送注册验证码
-    public function sendCode(Request $request)
-    {
-        $validator = Validator::make($request->all(), [
-            'username' => 'required|email|unique:user'
-        ], [
-            'username.required' => trans('auth.email_null'),
-            'username.email'    => trans('auth.email_legitimate'),
-            'username.unique'   => trans('auth.email_exist')
-        ]);
-
-        if ($validator->fails()) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => $validator->getMessageBag()->first()]);
-        }
-
-        // 校验域名邮箱是否在敏感词中
-        $sensitiveWords = $this->sensitiveWords();
-        $usernameSuffix = explode('@', $request->username); // 提取邮箱后缀
-        if (in_array(strtolower($usernameSuffix[1]), $sensitiveWords)) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => trans('auth.email_banned')]);
-        }
-
-        // 是否开启注册发送验证码
-        if (!self::$systemConfig['is_verify_register']) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => trans('auth.captcha_close')]);
-        }
-
-        // 防刷机制
-        if (Cache::has('send_verify_code_' . md5(getClientIP()))) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => trans('auth.register_anti')]);
-        }
-
-        // 发送邮件
-        $code = makeRandStr(6, true);
-        $logId = Helpers::addEmailLog($request->username, '发送注册验证码', '验证码:' . $code);
-        Mail::to($request->username)->send(new sendVerifyCode($logId, $code));
-
-        $this->addVerifyCode($request->username, $code);
-
-        Cache::put('send_verify_code_' . md5(getClientIP()), getClientIP(), 1);
-
-        return Response::json(['status' => 'success', 'data' => '', 'message' => trans('auth.captcha_send')]);
-    }
-
-    // 公开的邀请码列表
-    public function free(Request $request)
-    {
-        $view['inviteList'] = Invite::query()->where('uid', 0)->where('status', 0)->paginate();
-
-        return Response::view('auth.free', $view);
-    }
-
-    // 切换语言
-    public function switchLang(Request $request, $locale)
-    {
-        Session::put("locale", $locale);
-
-        return Redirect::back();
-    }
-
-    /**
-     * 添加用户登录日志
-     *
-     * @param string $userId 用户ID
-     * @param string $ip     IP地址
-     */
-    private function addUserLoginLog($userId, $ip)
-    {
-        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
-            Log::info('识别到IPv6,尝试解析:' . $ip);
-            $ipInfo = getIPv6($ip);
-        } else {
-            $ipInfo = QQWry::ip($ip); // 通过纯真IP库解析IPv4信息
-            if (isset($ipInfo['error'])) {
-                Log::info('无法识别IPv4,尝试使用IPIP的IP库解析:' . $ip);
-                $ipip = IPIP::ip($ip);
-                $ipInfo = [
-                    'country'  => $ipip['country_name'],
-                    'province' => $ipip['region_name'],
-                    'city'     => $ipip['city_name']
-                ];
-            } else {
-                // 判断纯真IP库获取的国家信息是否与IPIP的IP库获取的信息一致,不一致则用IPIP的(因为纯真IP库的非大陆IP准确率较低)
-                $ipip = IPIP::ip($ip);
-                if ($ipInfo['country'] != $ipip['country_name']) {
-                    $ipInfo['country'] = $ipip['country_name'];
-                    $ipInfo['province'] = $ipip['region_name'];
-                    $ipInfo['city'] = $ipip['city_name'];
-                }
-            }
-        }
-
-        if (empty($ipInfo) || empty($ipInfo['country'])) {
-            Log::warning("获取IP信息异常:" . $ip);
-        }
-
-        $log = new UserLoginLog();
-        $log->user_id = $userId;
-        $log->ip = $ip;
-        $log->country = $ipInfo['country'] ?? '';
-        $log->province = $ipInfo['province'] ?? '';
-        $log->city = $ipInfo['city'] ?? '';
-        $log->county = $ipInfo['county'] ?? '';
-        $log->isp = $ipInfo['isp'] ?? ($ipInfo['organization'] ?? '');
-        $log->area = $ipInfo['area'] ?? '';
-        $log->save();
-    }
-
-    /**
-     * 获取AFF
-     *
-     * @param string $code 邀请码
-     * @param int    $aff  URL中的aff参数
-     *
-     * @return array
-     */
-    private function getAff($code = '', $aff = '')
-    {
-        // 邀请人ID
-        $referral_uid = 0;
-
-        // 邀请码ID
-        $code_id = 0;
-
-        // 有邀请码先用邀请码,用谁的邀请码就给谁返利
-        if ($code) {
-            $inviteCode = Invite::query()->where('code', $code)->where('status', 0)->first();
-            if ($inviteCode) {
-                $referral_uid = $inviteCode->uid;
-                $code_id = $inviteCode->id;
-            }
-        }
-
-        // 没有用邀请码或者邀请码是管理员生成的,则检查cookie或者url链接
-        if (!$referral_uid) {
-            // 检查一下cookie里有没有aff
-            $cookieAff = \Request::hasCookie('register_aff') ? \Request::cookie('register_aff') : 0;
-            if ($cookieAff) {
-                $affUser = User::query()->where('id', $cookieAff)->exists();
-                $referral_uid = $affUser ? $cookieAff : 0;
-            } elseif ($aff) { // 如果cookie里没有aff,就再检查一下请求的url里有没有aff,因为有些人的浏览器会禁用了cookie,比如chrome开了隐私模式
-                $affUser = User::query()->where('id', $aff)->exists();
-                $referral_uid = $affUser ? $aff : 0;
-            }
-        }
-
-        return [
-            'referral_uid' => $referral_uid,
-            'code_id'      => $code_id
-        ];
-    }
-
-    // 写入生成激活账号验证记录
-    private function addVerify($userId, $token)
-    {
-        $verify = new Verify();
-        $verify->type = 1;
-        $verify->user_id = $userId;
-        $verify->token = $token;
-        $verify->status = 0;
-        $verify->save();
-    }
-
-    // 生成注册验证码
-    private function addVerifyCode($username, $code)
-    {
-        $verify = new VerifyCode();
-        $verify->username = $username;
-        $verify->code = $code;
-        $verify->status = 0;
-        $verify->save();
-    }
+	protected static $systemConfig;
+
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	// 登录
+	public function login(Request $request)
+	{
+		if($request->isMethod('POST')){
+			$this->validate($request, [
+				'username' => 'required',
+				'password' => 'required'
+			], [
+				'username.required' => trans('auth.email_null'),
+				'password.required' => trans('auth.password_null')
+			]);
+
+			// 是否校验验证码
+			switch(self::$systemConfig['is_captcha']){
+				case 1: // 默认图形验证码
+					if(!Captcha::check($request->captcha)){
+						return Redirect::back()->withInput()->withErrors(trans('auth.captcha_error'));
+					}
+					break;
+				case 2: // Geetest
+					$result = $this->validate($request, [
+						'geetest_challenge' => 'required|geetest'
+					], [
+						'geetest' => trans('auth.captcha_fail')
+					]);
+
+					if(!$result){
+						return Redirect::back()->withInput()->withErrors(trans('auth.fail_captcha'));
+					}
+					break;
+				case 3: // Google reCAPTCHA
+					$result = $this->validate($request, [
+						'g-recaptcha-response' => 'required|NoCaptcha'
+					]);
+
+					if(!$result){
+						return Redirect::back()->withInput()->withErrors(trans('auth.fail_captcha'));
+					}
+					break;
+				default: // 不启用验证码
+					break;
+			}
+
+			// 验证账号并创建会话
+			if(!Auth::attempt(['username' => $request->username, 'password' => $request->password], $request->remember)){
+				return Redirect::back()->withInput()->withErrors(trans('auth.login_error'));
+			}
+
+			// 校验普通用户账号状态
+			if(!Auth::user()->is_admin){
+				if(Auth::user()->status < 0){
+					Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
+
+					return Redirect::back()->withInput()->withErrors(trans('auth.login_ban', ['email' => self::$systemConfig['admin_email']]));
+				}
+
+				if(Auth::user()->status == 0 && self::$systemConfig['is_active_register']){
+					Auth::logout(); // 强制销毁会话,因为Auth::attempt的时候会产生会话
+
+					return Redirect::back()->withInput()->withErrors(trans('auth.active_tip').'<a href="/activeUser?username='.$request->username.'" target="_blank"><span style="color:#000">【'.trans('auth.active_account').'】</span></a>');
+				}
+			}
+
+			// 写入登录日志
+			$this->addUserLoginLog(Auth::user()->id, getClientIp());
+
+			// 更新登录信息
+			User::uid()->update(['last_login' => time()]);
+
+			// 根据权限跳转
+			if(Auth::user()->is_admin){
+				return Redirect::to('admin');
+			}
+
+			return Redirect::to('/');
+		}else{
+			if(Auth::check()){
+				if(Auth::user()->is_admin){
+					return Redirect::to('admin');
+				}
+
+				return Redirect::to('/');
+			}
+
+			return Response::view('auth.login');
+		}
+	}
+
+	// 退出
+	public function logout(Request $request)
+	{
+		Auth::logout();
+
+		return Redirect::to('login');
+	}
+
+	// 注册
+	public function register(Request $request)
+	{
+		$cacheKey = 'register_times_'.md5(getClientIp()); // 注册限制缓存key
+
+		if($request->isMethod('POST')){
+			$this->validate($request, [
+				'username'   => 'required|email|unique:user',
+				'password'   => 'required|min:6',
+				'repassword' => 'required|same:password',
+			], [
+				'username.required'   => trans('auth.email_null'),
+				'username.email'      => trans('auth.email_legitimate'),
+				'username.unique'     => trans('auth.email_exist'),
+				'password.required'   => trans('auth.password_null'),
+				'password.min'        => trans('auth.password_limit'),
+				'repassword.required' => trans('auth.retype_password'),
+				'repassword.same'     => trans('auth.password_same')
+			]);
+
+			// 防止重复提交
+			if($request->register_token != Session::get('register_token')){
+				return Redirect::back()->withInput()->withErrors(trans('auth.repeat_request'));
+			}else{
+				Session::forget('register_token');
+			}
+
+			// 是否开启注册
+			if(!self::$systemConfig['is_register']){
+				return Redirect::back()->withErrors(trans('auth.register_close'));
+			}
+
+			// 校验域名邮箱是否在敏感词中
+			$sensitiveWords = $this->sensitiveWords();
+			$usernameSuffix = explode('@', $request->username); // 提取邮箱后缀
+			if(in_array(strtolower($usernameSuffix[1]), $sensitiveWords)){
+				return Redirect::back()->withInput()->withErrors(trans('auth.email_banned'));
+			}
+
+			// 如果需要邀请注册
+			if(self::$systemConfig['is_invite_register']){
+				// 必须使用邀请码
+				if(self::$systemConfig['is_invite_register'] == 2 && !$request->code){
+					return Redirect::back()->withInput()->withErrors(trans('auth.code_null'));
+				}
+
+				// 校验邀请码合法性
+				if($request->code){
+					$codeEnable = Invite::query()->where('code', $request->code)->where('status', 0)->first();
+					if(!$codeEnable){
+						return Redirect::back()->withInput($request->except(['code']))->withErrors(trans('auth.code_error'));
+					}
+				}
+			}
+
+			// 如果开启注册发送验证码
+			if(self::$systemConfig['is_verify_register']){
+				if(!$request->verify_code){
+					return Redirect::back()->withInput($request->except(['verify_code']))->withErrors(trans('auth.captcha_null'));
+				}else{
+					$verifyCode = VerifyCode::query()->where('username', $request->username)->where('code', $request->verify_code)->where('status', 0)->first();
+					if(!$verifyCode){
+						return Redirect::back()->withInput($request->except(['verify_code']))->withErrors(trans('auth.captcha_overtime'));
+					}
+
+					$verifyCode->status = 1;
+					$verifyCode->save();
+				}
+			}elseif(self::$systemConfig['is_captcha']){ // 是否校验验证码
+				switch(self::$systemConfig['is_captcha']){
+					case 1: // 默认图形验证码
+						if(!Captcha::check($request->captcha)){
+							return Redirect::back()->withInput()->withErrors(trans('auth.captcha_error'));
+						}
+						break;
+					case 2: // Geetest
+						$result = $this->validate($request, [
+							'geetest_challenge' => 'required|geetest'
+						], [
+							'geetest' => trans('auth.captcha_fail')
+						]);
+
+						if(!$result){
+							return Redirect::back()->withInput()->withErrors(trans('auth.captcha_fail'));
+						}
+						break;
+					case 3: // Google reCAPTCHA
+						$result = $this->validate($request, [
+							'g-recaptcha-response' => 'required|NoCaptcha'
+						]);
+
+						if(!$result){
+							return Redirect::back()->withInput()->withErrors(trans('auth.captcha_fail'));
+						}
+						break;
+					default: // 不启用验证码
+						break;
+				}
+			}
+
+			// 24小时内同IP注册限制
+			if(self::$systemConfig['register_ip_limit']){
+				if(Cache::has($cacheKey)){
+					$registerTimes = Cache::get($cacheKey);
+					if($registerTimes >= self::$systemConfig['register_ip_limit']){
+						return Redirect::back()->withInput($request->except(['code']))->withErrors(trans('auth.register_anti'));
+					}
+				}
+			}
+
+			// 获取可用端口
+			$port = self::$systemConfig['is_rand_port']? Helpers::getRandPort() : Helpers::getOnlyPort();
+			if($port > self::$systemConfig['max_port']){
+				return Redirect::back()->withInput()->withErrors(trans('auth.register_close'));
+			}
+
+			// 获取aff
+			$affArr = $this->getAff($request->code, intval($request->aff));
+			$referral_uid = $affArr['referral_uid'];
+
+			$transfer_enable = $referral_uid? (self::$systemConfig['default_traffic']+self::$systemConfig['referral_traffic'])*1048576 : self::$systemConfig['default_traffic']*1048576;
+
+			// 创建新用户
+			$user = new User();
+			$user->username = $request->username;
+			$user->password = Hash::make($request->password);
+			$user->port = $port;
+			$user->passwd = makeRandStr();
+			$user->vmess_id = createGuid();
+			$user->transfer_enable = $transfer_enable;
+			$user->method = Helpers::getDefaultMethod();
+			$user->protocol = Helpers::getDefaultProtocol();
+			$user->obfs = Helpers::getDefaultObfs();
+			$user->enable_time = date('Y-m-d H:i:s');
+			$user->expire_time = date('Y-m-d H:i:s', strtotime("+".self::$systemConfig['default_days']." days"));
+			$user->reg_ip = getClientIp();
+			$user->referral_uid = $referral_uid;
+			$user->save();
+
+			// 注册失败,抛出异常
+			if(!$user->id){
+				return Redirect::back()->withInput()->withErrors(trans('auth.register_fail'));
+			}
+
+			// 生成订阅码
+			$subscribe = new UserSubscribe();
+			$subscribe->user_id = $user->id;
+			$subscribe->code = Helpers::makeSubscribeCode();
+			$subscribe->times = 0;
+			$subscribe->save();
+
+			// 注册次数+1
+			if(Cache::has($cacheKey)){
+				Cache::increment($cacheKey);
+			}else{
+				Cache::put($cacheKey, 1, 1440); // 24小时
+			}
+
+			// 初始化默认标签
+			if(strlen(self::$systemConfig['initial_labels_for_user'])){
+				$labels = explode(',', self::$systemConfig['initial_labels_for_user']);
+				foreach($labels as $label){
+					$userLabel = new UserLabel();
+					$userLabel->user_id = $user->id;
+					$userLabel->label_id = $label;
+					$userLabel->save();
+				}
+			}
+
+			// 更新邀请码
+			if(self::$systemConfig['is_invite_register'] && $affArr['code_id']){
+				Invite::query()->where('id', $affArr['code_id'])->update(['fuid' => $user->id, 'status' => 1]);
+			}
+
+			// 清除邀请人Cookie
+			Cookie::unqueue('register_aff');
+
+			if(self::$systemConfig['is_verify_register']){
+				if($referral_uid){
+					$transfer_enable = self::$systemConfig['referral_traffic']*1048576;
+
+					User::query()->where('id', $referral_uid)->increment('transfer_enable', $transfer_enable);
+					User::query()->where('id', $referral_uid)->update(['status' => 1, 'enable' => 1]);
+				}
+
+				User::query()->where('id', $user->id)->update(['status' => 1, 'enable' => 1]);
+
+				Session::flash('regSuccessMsg', trans('auth.register_success'));
+			}else{
+				// 发送激活邮件
+				if(self::$systemConfig['is_active_register']){
+					// 生成激活账号的地址
+					$token = md5(self::$systemConfig['website_name'].$request->username.microtime());
+					$activeUserUrl = self::$systemConfig['website_url'].'/active/'.$token;
+					$this->addVerify($user->id, $token);
+
+					$logId = Helpers::addEmailLog($request->username, '注册激活', '请求地址:'.$activeUserUrl);
+					Mail::to($request->username)->send(new activeUser($logId, $activeUserUrl));
+
+					Session::flash('regSuccessMsg', trans('auth.register_success_tip'));
+				}else{
+					// 如果不需要激活,则直接给推荐人加流量
+					if($referral_uid){
+						$transfer_enable = self::$systemConfig['referral_traffic']*1048576;
+
+						User::query()->where('id', $referral_uid)->increment('transfer_enable', $transfer_enable);
+						User::query()->where('id', $referral_uid)->update(['status' => 1, 'enable' => 1]);
+					}
+
+					User::query()->where('id', $user->id)->update(['status' => 1, 'enable' => 1]);
+
+					Session::flash('regSuccessMsg', trans('auth.register_success'));
+				}
+			}
+
+			return Redirect::to('login')->withInput();
+		}else{
+			Session::put('register_token', makeRandStr(16));
+
+			return Response::view('auth.register');
+		}
+	}
+
+	// 重设密码页
+	public function resetPassword(Request $request)
+	{
+		if($request->isMethod('POST')){
+			// 校验请求
+			$this->validate($request, [
+				'username' => 'required|email'
+			], [
+				'username.required' => trans('auth.email_null'),
+				'username.email'    => trans('auth.email_legitimate')
+			]);
+
+			// 是否开启重设密码
+			if(!self::$systemConfig['is_reset_password']){
+				return Redirect::back()->withErrors(trans('auth.reset_password_close', ['email' => self::$systemConfig['admin_email']]));
+			}
+
+			// 查找账号
+			$user = User::query()->where('username', $request->username)->first();
+			if(!$user){
+				return Redirect::back()->withErrors(trans('auth.email_notExist'));
+			}
+
+			// 24小时内重设密码次数限制
+			$resetTimes = 0;
+			if(Cache::has('resetPassword_'.md5($request->username))){
+				$resetTimes = Cache::get('resetPassword_'.md5($request->username));
+				if($resetTimes >= self::$systemConfig['reset_password_times']){
+					return Redirect::back()->withErrors(trans('auth.reset_password_limit', ['time' => self::$systemConfig['reset_password_times']]));
+				}
+			}
+
+			// 生成取回密码的地址
+			$token = md5(self::$systemConfig['website_name'].$request->username.microtime());
+			$verify = new Verify();
+			$verify->type = 1;
+			$verify->user_id = $user->id;
+			$verify->token = $token;
+			$verify->status = 0;
+			$verify->save();
+
+			// 发送邮件
+			$resetPasswordUrl = self::$systemConfig['website_url'].'/reset/'.$token;
+
+			$logId = Helpers::addEmailLog($request->username, '重置密码', '请求地址:'.$resetPasswordUrl);
+			Mail::to($request->username)->send(new resetPassword($logId, $resetPasswordUrl));
+
+			Cache::put('resetPassword_'.md5($request->username), $resetTimes+1, 1440);
+
+			return Redirect::back()->with('successMsg', trans('auth.reset_password_success_tip'));
+		}else{
+			return Response::view('auth.resetPassword');
+		}
+	}
+
+	// 重设密码
+	public function reset(Request $request, $token)
+	{
+		if(!$token){
+			return Redirect::to('login');
+		}
+
+		if($request->isMethod('POST')){
+			$this->validate($request, [
+				'password'   => 'required|min:6',
+				'repassword' => 'required|same:password'
+			], [
+				'password.required'   => trans('auth.password_null'),
+				'password.min'        => trans('auth.password_limit'),
+				'repassword.required' => trans('auth.password_null'),
+				'repassword.min'      => trans('auth.password_limit'),
+				'repassword.same'     => trans('auth.password_same'),
+			]);
+
+			// 校验账号
+			$verify = Verify::type(1)->with('user')->where('token', $token)->first();
+			if(!$verify){
+				return Redirect::to('login');
+			}elseif($verify->status == 1){
+				return Redirect::back()->withErrors(trans('auth.overtime'));
+			}elseif($verify->user->status < 0){
+				return Redirect::back()->withErrors(trans('auth.email_banned'));
+			}elseif(Hash::check($request->password, $verify->user->password)){
+				return Redirect::back()->withErrors(trans('auth.rest_password_same_fail'));
+			}
+
+			// 更新密码
+			$ret = User::query()->where('id', $verify->user_id)->update(['password' => Hash::make($request->password)]);
+			if(!$ret){
+				return Redirect::back()->withErrors(trans('auth.rest_password_fail'));
+			}
+
+			// 置为已使用
+			$verify->status = 1;
+			$verify->save();
+
+			return Redirect::back()->with('successMsg', trans('auth.reset_password_new'));
+		}else{
+			$verify = Verify::type(1)->where('token', $token)->first();
+			if(!$verify){
+				return Redirect::to('login');
+			}elseif(time()-strtotime($verify->created_at) >= 1800){
+				// 置为已失效
+				$verify->status = 2;
+				$verify->save();
+			}
+
+			// 重新获取一遍verify
+			$view['verify'] = Verify::type(1)->where('token', $token)->first();
+
+			return Response::view('auth.reset', $view);
+		}
+	}
+
+	// 激活账号页
+	public function activeUser(Request $request)
+	{
+		if($request->isMethod('POST')){
+			$this->validate($request, [
+				'username' => 'required|email|exists:user,username'
+			], [
+				'username.required' => trans('auth.email_null'),
+				'username.email'    => trans('auth.email_legitimate'),
+				'username.exists'   => trans('auth.email_notExist')
+			]);
+
+			// 是否开启账号激活
+			if(!self::$systemConfig['is_active_register']){
+				return Redirect::back()->withInput()->withErrors(trans('auth.active_close', ['email' => self::$systemConfig['admin_email']]));
+			}
+
+			// 查找账号
+			$user = User::query()->where('username', $request->username)->first();
+			if($user->status < 0){
+				return Redirect::back()->withErrors(trans('auth.login_ban', ['email' => self::$systemConfig['admin_email']]));
+			}elseif($user->status > 0){
+				return Redirect::back()->withErrors(trans('auth.email_normal'));
+			}
+
+			// 24小时内激活次数限制
+			$activeTimes = 0;
+			if(Cache::has('activeUser_'.md5($request->username))){
+				$activeTimes = Cache::get('activeUser_'.md5($request->username));
+				if($activeTimes >= self::$systemConfig['active_times']){
+					return Redirect::back()->withErrors(trans('auth.active_limit', ['time' => self::$systemConfig['admin_email']]));
+				}
+			}
+
+			// 生成激活账号的地址
+			$token = md5(self::$systemConfig['website_name'].$request->username.microtime());
+			$verify = new Verify();
+			$verify->type = 1;
+			$verify->user_id = $user->id;
+			$verify->token = $token;
+			$verify->status = 0;
+			$verify->save();
+
+			// 发送邮件
+			$activeUserUrl = self::$systemConfig['website_url'].'/active/'.$token;
+
+			$logId = Helpers::addEmailLog($request->username, '激活账号', '请求地址:'.$activeUserUrl);
+			Mail::to($request->username)->send(new activeUser($logId, $activeUserUrl));
+
+			Cache::put('activeUser_'.md5($request->username), $activeTimes+1, 1440);
+
+			return Redirect::back()->with('successMsg', trans('auth.register_success_tip'));
+		}else{
+			return Response::view('auth.activeUser');
+		}
+	}
+
+	// 激活账号
+	public function active(Request $request, $token)
+	{
+		if(!$token){
+			return Redirect::to('login');
+		}
+
+		$verify = Verify::type(1)->with('user')->where('token', $token)->first();
+		if(!$verify){
+			return Redirect::to('login');
+		}elseif(empty($verify->user)){
+			Session::flash('errorMsg', trans('auth.overtime'));
+
+			return Response::view('auth.active');
+		}elseif($verify->status > 0){
+			Session::flash('errorMsg', trans('auth.overtime'));
+
+			return Response::view('auth.active');
+		}elseif($verify->user->status != 0){
+			Session::flash('errorMsg', trans('auth.email_normal'));
+
+			return Response::view('auth.active');
+		}elseif(time()-strtotime($verify->created_at) >= 1800){
+			Session::flash('errorMsg', trans('auth.overtime'));
+
+			// 置为已失效
+			$verify->status = 2;
+			$verify->save();
+
+			return Response::view('auth.active');
+		}
+
+		// 更新账号状态
+		$ret = User::query()->where('id', $verify->user_id)->update(['status' => 1]);
+		if(!$ret){
+			Session::flash('errorMsg', trans('auth.active_fail'));
+
+			return Redirect::back();
+		}
+
+		// 置为已使用
+		$verify->status = 1;
+		$verify->save();
+
+		// 账号激活后给邀请人送流量
+		if($verify->user->referral_uid){
+			$transfer_enable = self::$systemConfig['referral_traffic']*1048576;
+
+			User::query()->where('id', $verify->user->referral_uid)->increment('transfer_enable', $transfer_enable);
+			User::query()->where('id', $verify->user->referral_uid)->update(['enable' => 1]);
+		}
+
+		Session::flash('successMsg', trans('auth.active_success'));
+
+		return Response::view('auth.active');
+	}
+
+	// 发送注册验证码
+	public function sendCode(Request $request)
+	{
+		$validator = Validator::make($request->all(), [
+			'username' => 'required|email|unique:user'
+		], [
+			'username.required' => trans('auth.email_null'),
+			'username.email'    => trans('auth.email_legitimate'),
+			'username.unique'   => trans('auth.email_exist')
+		]);
+
+		if($validator->fails()){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => $validator->getMessageBag()->first()]);
+		}
+
+		// 校验域名邮箱是否在敏感词中
+		$sensitiveWords = $this->sensitiveWords();
+		$usernameSuffix = explode('@', $request->username); // 提取邮箱后缀
+		if(in_array(strtolower($usernameSuffix[1]), $sensitiveWords)){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => trans('auth.email_banned')]);
+		}
+
+		// 是否开启注册发送验证码
+		if(!self::$systemConfig['is_verify_register']){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => trans('auth.captcha_close')]);
+		}
+
+		// 防刷机制
+		if(Cache::has('send_verify_code_'.md5(getClientIP()))){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => trans('auth.register_anti')]);
+		}
+
+		// 发送邮件
+		$code = makeRandStr(6, TRUE);
+		$logId = Helpers::addEmailLog($request->username, '发送注册验证码', '验证码:'.$code);
+		Mail::to($request->username)->send(new sendVerifyCode($logId, $code));
+
+		$this->addVerifyCode($request->username, $code);
+
+		Cache::put('send_verify_code_'.md5(getClientIP()), getClientIP(), 1);
+
+		return Response::json(['status' => 'success', 'data' => '', 'message' => trans('auth.captcha_send')]);
+	}
+
+	// 公开的邀请码列表
+	public function free(Request $request)
+	{
+		$view['inviteList'] = Invite::query()->where('uid', 0)->where('status', 0)->paginate();
+
+		return Response::view('auth.free', $view);
+	}
+
+	// 切换语言
+	public function switchLang(Request $request, $locale)
+	{
+		Session::put("locale", $locale);
+
+		return Redirect::back();
+	}
+
+	/**
+	 * 添加用户登录日志
+	 *
+	 * @param string $userId 用户ID
+	 * @param string $ip     IP地址
+	 */
+	private function addUserLoginLog($userId, $ip)
+	{
+		if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)){
+			Log::info('识别到IPv6,尝试解析:'.$ip);
+			$ipInfo = getIPv6($ip);
+		}else{
+			$ipInfo = QQWry::ip($ip); // 通过纯真IP库解析IPv4信息
+			if(isset($ipInfo['error'])){
+				Log::info('无法识别IPv4,尝试使用IPIP的IP库解析:'.$ip);
+				$ipip = IPIP::ip($ip);
+				$ipInfo = [
+					'country'  => $ipip['country_name'],
+					'province' => $ipip['region_name'],
+					'city'     => $ipip['city_name']
+				];
+			}else{
+				// 判断纯真IP库获取的国家信息是否与IPIP的IP库获取的信息一致,不一致则用IPIP的(因为纯真IP库的非大陆IP准确率较低)
+				$ipip = IPIP::ip($ip);
+				if($ipInfo['country'] != $ipip['country_name']){
+					$ipInfo['country'] = $ipip['country_name'];
+					$ipInfo['province'] = $ipip['region_name'];
+					$ipInfo['city'] = $ipip['city_name'];
+				}
+			}
+		}
+
+		if(empty($ipInfo) || empty($ipInfo['country'])){
+			Log::warning("获取IP信息异常:".$ip);
+		}
+
+		$log = new UserLoginLog();
+		$log->user_id = $userId;
+		$log->ip = $ip;
+		$log->country = $ipInfo['country'] ?? '';
+		$log->province = $ipInfo['province'] ?? '';
+		$log->city = $ipInfo['city'] ?? '';
+		$log->county = $ipInfo['county'] ?? '';
+		$log->isp = $ipInfo['isp'] ?? ($ipInfo['organization'] ?? '');
+		$log->area = $ipInfo['area'] ?? '';
+		$log->save();
+	}
+
+	/**
+	 * 获取AFF
+	 *
+	 * @param string $code 邀请码
+	 * @param int    $aff  URL中的aff参数
+	 *
+	 * @return array
+	 */
+	private function getAff($code = '', $aff = '')
+	{
+		// 邀请人ID
+		$referral_uid = 0;
+
+		// 邀请码ID
+		$code_id = 0;
+
+		// 有邀请码先用邀请码,用谁的邀请码就给谁返利
+		if($code){
+			$inviteCode = Invite::query()->where('code', $code)->where('status', 0)->first();
+			if($inviteCode){
+				$referral_uid = $inviteCode->uid;
+				$code_id = $inviteCode->id;
+			}
+		}
+
+		// 没有用邀请码或者邀请码是管理员生成的,则检查cookie或者url链接
+		if(!$referral_uid){
+			// 检查一下cookie里有没有aff
+			$cookieAff = \Request::hasCookie('register_aff')? \Request::cookie('register_aff') : 0;
+			if($cookieAff){
+				$affUser = User::query()->where('id', $cookieAff)->exists();
+				$referral_uid = $affUser? $cookieAff : 0;
+			}elseif($aff){ // 如果cookie里没有aff,就再检查一下请求的url里有没有aff,因为有些人的浏览器会禁用了cookie,比如chrome开了隐私模式
+				$affUser = User::query()->where('id', $aff)->exists();
+				$referral_uid = $affUser? $aff : 0;
+			}
+		}
+
+		return [
+			'referral_uid' => $referral_uid,
+			'code_id'      => $code_id
+		];
+	}
+
+	// 写入生成激活账号验证记录
+	private function addVerify($userId, $token)
+	{
+		$verify = new Verify();
+		$verify->type = 1;
+		$verify->user_id = $userId;
+		$verify->token = $token;
+		$verify->status = 0;
+		$verify->save();
+	}
+
+	// 生成注册验证码
+	private function addVerifyCode($username, $code)
+	{
+		$verify = new VerifyCode();
+		$verify->username = $username;
+		$verify->code = $code;
+		$verify->status = 0;
+		$verify->save();
+	}
 }

+ 152 - 151
app/Http/Controllers/Controller.php

@@ -5,6 +5,7 @@ namespace App\Http\Controllers;
 use App\Http\Models\ReferralLog;
 use App\Http\Models\SensitiveWords;
 use App\Http\Models\UserBalanceLog;
+use Exception;
 use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
 use Illuminate\Foundation\Bus\DispatchesJobs;
 use Illuminate\Foundation\Validation\ValidatesRequests;
@@ -12,155 +13,155 @@ use Illuminate\Routing\Controller as BaseController;
 
 class Controller extends BaseController
 {
-    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
-
-    // 生成随机密码
-    public function makePasswd()
-    {
-        exit(makeRandStr());
-    }
-
-    // 生成VmessId
-    public function makeVmessId()
-    {
-        exit(createGuid());
-    }
-
-    // 生成网站安全码
-    public function makeSecurityCode()
-    {
-        exit(strtolower(makeRandStr(8)));
-    }
-
-    // 类似Linux中的tail命令
-    public function tail($file, $n, $base = 5)
-    {
-        $fileLines = $this->countLine($file);
-        if ($fileLines < 15000) {
-            return false;
-        }
-
-        $fp = fopen($file, "r+");
-        assert($n > 0);
-        $pos = $n + 1;
-        $lines = [];
-        while (count($lines) <= $n) {
-            try {
-                fseek($fp, -$pos, SEEK_END);
-            } catch (\Exception $e) {
-                fseek(0);
-                break;
-            }
-
-            $pos *= $base;
-            while (!feof($fp)) {
-                array_unshift($lines, fgets($fp));
-            }
-        }
-
-        return array_slice($lines, 0, $n);
-    }
-
-    /**
-     * 计算文件行数
-     */
-    public function countLine($file)
-    {
-        $fp = fopen($file, "r");
-        $i = 0;
-        while (!feof($fp)) {
-            //每次读取2M
-            if ($data = fread($fp, 1024 * 1024 * 2)) {
-                //计算读取到的行数
-                $num = substr_count($data, "\n");
-                $i += $num;
-            }
-        }
-
-        fclose($fp);
-
-        return $i;
-    }
-
-    /**
-     * 记录余额操作日志
-     *
-     * @param int    $userId 用户ID
-     * @param string $oid    订单ID
-     * @param int    $before 记录前余额
-     * @param int    $after  记录后余额
-     * @param int    $amount 发生金额
-     * @param string $desc   描述
-     *
-     * @return int
-     */
-    public function addUserBalanceLog($userId, $oid, $before, $after, $amount, $desc = '')
-    {
-        $log = new UserBalanceLog();
-        $log->user_id = $userId;
-        $log->order_id = $oid;
-        $log->before = $before;
-        $log->after = $after;
-        $log->amount = $amount;
-        $log->desc = $desc;
-        $log->created_at = date('Y-m-d H:i:s');
-
-        return $log->save();
-    }
-
-    /**
-     * 添加返利日志
-     *
-     * @param int $userId    用户ID
-     * @param int $refUserId 返利用户ID
-     * @param int $oid       订单ID
-     * @param int $amount    发生金额
-     * @param int $refAmount 返利金额
-     *
-     * @return int
-     */
-    public function addReferralLog($userId, $refUserId, $oid, $amount, $refAmount)
-    {
-        $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();
-    }
-
-    // 获取敏感词
-    public function sensitiveWords()
-    {
-        return SensitiveWords::query()->get()->pluck('words')->toArray();
-    }
-
-    // 将Base64图片转换为本地图片并保存
-    function base64ImageSaver($base64_image_content)
-    {
-        // 匹配出图片的格式
-        if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image_content, $result)) {
-            $type = $result[2];
-
-            $directory = date('Ymd');
-            $path = '/assets/images/qrcode/' . $directory . '/';
-            if (!file_exists(public_path($path))) { // 检查是否有该文件夹,如果没有就创建,并给予最高权限
-                mkdir(public_path($path), 0755, true);
-            }
-
-            $fileName = makeRandStr(18, true) . ".{$type}";
-            if (file_put_contents(public_path($path . $fileName), base64_decode(str_replace($result[1], '', $base64_image_content)))) {
-                chmod(public_path($path . $fileName), 0744);
-
-                return $path . $fileName;
-            } else {
-                return '';
-            }
-        } else {
-            return '';
-        }
-    }
+	use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
+
+	// 生成随机密码
+	public function makePasswd()
+	{
+		exit(makeRandStr());
+	}
+
+	// 生成VmessId
+	public function makeVmessId()
+	{
+		exit(createGuid());
+	}
+
+	// 生成网站安全码
+	public function makeSecurityCode()
+	{
+		exit(strtolower(makeRandStr(8)));
+	}
+
+	// 类似Linux中的tail命令
+	public function tail($file, $n, $base = 5)
+	{
+		$fileLines = $this->countLine($file);
+		if($fileLines < 15000){
+			return FALSE;
+		}
+
+		$fp = fopen($file, "r+");
+		assert($n > 0);
+		$pos = $n+1;
+		$lines = [];
+		while(count($lines) <= $n){
+			try{
+				fseek($fp, -$pos, SEEK_END);
+			} catch(Exception $e){
+				fseek(0);
+				break;
+			}
+
+			$pos *= $base;
+			while(!feof($fp)){
+				array_unshift($lines, fgets($fp));
+			}
+		}
+
+		return array_slice($lines, 0, $n);
+	}
+
+	/**
+	 * 计算文件行数
+	 */
+	public function countLine($file)
+	{
+		$fp = fopen($file, "r");
+		$i = 0;
+		while(!feof($fp)){
+			//每次读取2M
+			if($data = fread($fp, 1024*1024*2)){
+				//计算读取到的行数
+				$num = substr_count($data, "\n");
+				$i += $num;
+			}
+		}
+
+		fclose($fp);
+
+		return $i;
+	}
+
+	/**
+	 * 记录余额操作日志
+	 *
+	 * @param int    $userId 用户ID
+	 * @param string $oid    订单ID
+	 * @param int    $before 记录前余额
+	 * @param int    $after  记录后余额
+	 * @param int    $amount 发生金额
+	 * @param string $desc   描述
+	 *
+	 * @return int
+	 */
+	public function addUserBalanceLog($userId, $oid, $before, $after, $amount, $desc = '')
+	{
+		$log = new UserBalanceLog();
+		$log->user_id = $userId;
+		$log->order_id = $oid;
+		$log->before = $before;
+		$log->after = $after;
+		$log->amount = $amount;
+		$log->desc = $desc;
+		$log->created_at = date('Y-m-d H:i:s');
+
+		return $log->save();
+	}
+
+	/**
+	 * 添加返利日志
+	 *
+	 * @param int $userId    用户ID
+	 * @param int $refUserId 返利用户ID
+	 * @param int $oid       订单ID
+	 * @param int $amount    发生金额
+	 * @param int $refAmount 返利金额
+	 *
+	 * @return int
+	 */
+	public function addReferralLog($userId, $refUserId, $oid, $amount, $refAmount)
+	{
+		$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();
+	}
+
+	// 获取敏感词
+	public function sensitiveWords()
+	{
+		return SensitiveWords::query()->get()->pluck('words')->toArray();
+	}
+
+	// 将Base64图片转换为本地图片并保存
+	function base64ImageSaver($base64_image_content)
+	{
+		// 匹配出图片的格式
+		if(preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image_content, $result)){
+			$type = $result[2];
+
+			$directory = date('Ymd');
+			$path = '/assets/images/qrcode/'.$directory.'/';
+			if(!file_exists(public_path($path))){ // 检查是否有该文件夹,如果没有就创建,并给予最高权限
+				mkdir(public_path($path), 0755, TRUE);
+			}
+
+			$fileName = makeRandStr(18, TRUE).".{$type}";
+			if(file_put_contents(public_path($path.$fileName), base64_decode(str_replace($result[1], '', $base64_image_content)))){
+				chmod(public_path($path.$fileName), 0744);
+
+				return $path.$fileName;
+			}else{
+				return '';
+			}
+		}else{
+			return '';
+		}
+	}
 }

+ 145 - 145
app/Http/Controllers/CouponController.php

@@ -21,149 +21,149 @@ use Response;
  */
 class CouponController extends Controller
 {
-    // 优惠券列表
-    public function couponList(Request $request)
-    {
-        $sn = $request->input('sn');
-        $type = $request->input('type');
-        $status = $request->input('status');
-
-        $query = Coupon::query();
-
-        if (isset($sn)) {
-            $query->where('sn', 'like', '%' . $sn . '%');
-        }
-
-        if (isset($type)) {
-            $query->where('type', $type);
-        }
-
-        if (isset($status)) {
-            $query->where('status', $status);
-        }
-
-        $view['couponList'] = $query->orderBy('id', 'desc')->paginate(15)->appends($request->except('page'));
-
-        return Response::view('coupon.couponList', $view);
-    }
-
-    // 添加商品
-    public function addCoupon(Request $request)
-    {
-        if ($request->isMethod('POST')) {
-            $this->validate($request, ['name' => 'required', 'type' => 'required|integer|between:1,3', 'usage' => 'required|integer|between:1,2', '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' => '请填入卡券名称', 'type.required' => '请选择卡券类型', 'type.integer' => '卡券类型不合法,请重选', 'type.between' => '卡券类型不合法,请重选', 'usage.required' => '请选择卡券用途', 'usage.integer' => '卡券用途不合法,请重选', 'usage.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' => '有效期不合法']);
-
-            // 优惠卷LOGO
-            if ($request->hasFile('logo')) {
-                $file = $request->file('logo');
-                $fileType = $file->getClientOriginalExtension();
-
-                // 验证文件合法性
-                if (!in_array($fileType, ['jpg', 'png', 'jpeg', 'bmp'])) {
-                    return Redirect::back()->withInput()->withErrors('LOGO不合法');
-                }
-
-                $logoName = date('YmdHis') . mt_rand(1000, 2000) . '.' . $fileType;
-                $move = $file->move(base_path() . '/public/upload/image/', $logoName);
-                $logo = $move ? '/upload/image/' . $logoName : '';
-            } else {
-                $logo = '';
-            }
-
-            DB::beginTransaction();
-            try {
-                for ($i = 0; $i < $request->num; $i++) {
-                    $obj = new Coupon();
-                    $obj->name = $request->name;
-                    $obj->sn = empty($request->sn) ? strtoupper(makeRandStr(8)) : $request->sn;
-                    $obj->logo = $logo;
-                    $obj->type = $request->type;
-                    $obj->usage = $request->usage;
-                    $obj->amount = $request->type == 2 ? 0 : $request->amount;
-                    $obj->discount = $request->type != 2 ? 0 : $request->discount;
-                    $obj->available_start = strtotime(date('Y-m-d 00:00:00', strtotime($request->available_start)));
-                    $obj->available_end = strtotime(date('Y-m-d 23:59:59', strtotime($request->available_end)));
-                    $obj->status = 0;
-                    $obj->save();
-                }
-
-                DB::commit();
-
-                return Redirect::back()->with('successMsg', '生成成功');
-            } catch (Exception $e) {
-                DB::rollBack();
-
-                Log::error('生成优惠券失败:' . $e->getMessage());
-
-                return Redirect::back()->withInput()->withErrors('生成失败:' . $e->getMessage());
-            }
-        } else {
-            return Response::view('coupon.addCoupon');
-        }
-    }
-
-    // 删除优惠券
-    public function delCoupon(Request $request)
-    {
-        Coupon::query()->where('id', $request->input('id'))->delete();
-
-        return Response::json(['status' => 'success', 'data' => '', 'message' => '删除成功']);
-    }
-
-    // 导出卡券
-    public function exportCoupon(Request $request)
-    {
-        $cashCouponList = Coupon::type(1)->where('status', 0)->get();
-        $discountCouponList = Coupon::type(2)->where('status', 0)->get();
-        $chargeCouponList = Coupon::type(3)->where('status', 0)->get();
-
-        $filename = '卡券' . date('Ymd') . '.xlsx';
-        $spreadsheet = new Spreadsheet();
-        $spreadsheet->getProperties()->setCreator('SSRPanel')->setLastModifiedBy('SSRPanel')->setTitle('邀请码')->setSubject('邀请码')->setDescription('')->setKeywords('')->setCategory('');
-
-        // 抵用券
-        $spreadsheet->setActiveSheetIndex(0);
-        $sheet = $spreadsheet->getActiveSheet();
-        $sheet->setTitle('抵用券');
-        $sheet->fromArray(['名称', '类型', '有效期', '券码', '金额(元)'], null);
-        foreach ($cashCouponList as $k => $vo) {
-            $usage = $vo->usage == 1 ? '一次性' : '重复使用';
-            $dateRange = date('Y-m-d', $vo->available_start) . ' ~ ' . date('Y-m-d', $vo->available_end);
-            $sheet->fromArray([$vo->name, $usage, $dateRange, $vo->sn, $vo->amount], null, 'A' . ($k + 2));
-        }
-
-        // 折扣券
-        $spreadsheet->createSheet(1);
-        $spreadsheet->setActiveSheetIndex(1);
-        $sheet = $spreadsheet->getActiveSheet();
-        $sheet->setTitle('折扣券');
-        $sheet->fromArray(['名称', '类型', '有效期', '券码', '折扣(折)'], null);
-        foreach ($discountCouponList as $k => $vo) {
-            $usage = $vo->usage == 1 ? '一次性' : '重复使用';
-            $dateRange = date('Y-m-d', $vo->available_start) . ' ~ ' . date('Y-m-d', $vo->available_end);
-            $sheet->fromArray([$vo->name, $usage, $dateRange, $vo->sn, $vo->discount], null, 'A' . ($k + 2));
-        }
-
-        // 充值券
-        $spreadsheet->createSheet(2);
-        $spreadsheet->setActiveSheetIndex(2);
-        $sheet = $spreadsheet->getActiveSheet();
-        $sheet->setTitle('充值券');
-        $sheet->fromArray(['名称', '类型', '有效期', '券码', '金额(元)'], null);
-        foreach ($chargeCouponList as $k => $vo) {
-            $usage = '一次性';
-            $dateRange = date('Y-m-d', $vo->available_start) . ' ~ ' . date('Y-m-d', $vo->available_end);
-            $sheet->fromArray([$vo->name, $usage, $dateRange, $vo->sn, $vo->amount], null, 'A' . ($k + 2));
-        }
-
-        // 指针切换回第一个sheet
-        $spreadsheet->setActiveSheetIndex(0);
-
-        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); // 输出07Excel文件
-        //header('Content-Type:application/vnd.ms-excel'); // 输出Excel03版本文件
-        header('Content-Disposition: attachment;filename="' . $filename . '"');
-        header('Cache-Control: max-age=0');
-        $writer = new Xlsx($spreadsheet);
-        $writer->save('php://output');
-    }
+	// 优惠券列表
+	public function couponList(Request $request)
+	{
+		$sn = $request->input('sn');
+		$type = $request->input('type');
+		$status = $request->input('status');
+
+		$query = Coupon::query();
+
+		if(isset($sn)){
+			$query->where('sn', 'like', '%'.$sn.'%');
+		}
+
+		if(isset($type)){
+			$query->where('type', $type);
+		}
+
+		if(isset($status)){
+			$query->where('status', $status);
+		}
+
+		$view['couponList'] = $query->orderBy('id', 'desc')->paginate(15)->appends($request->except('page'));
+
+		return Response::view('coupon.couponList', $view);
+	}
+
+	// 添加商品
+	public function addCoupon(Request $request)
+	{
+		if($request->isMethod('POST')){
+			$this->validate($request, ['name' => 'required', 'type' => 'required|integer|between:1,3', 'usage' => 'required|integer|between:1,2', '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' => '请填入卡券名称', 'type.required' => '请选择卡券类型', 'type.integer' => '卡券类型不合法,请重选', 'type.between' => '卡券类型不合法,请重选', 'usage.required' => '请选择卡券用途', 'usage.integer' => '卡券用途不合法,请重选', 'usage.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' => '有效期不合法']);
+
+			// 优惠卷LOGO
+			if($request->hasFile('logo')){
+				$file = $request->file('logo');
+				$fileType = $file->getClientOriginalExtension();
+
+				// 验证文件合法性
+				if(!in_array($fileType, ['jpg', 'png', 'jpeg', 'bmp'])){
+					return Redirect::back()->withInput()->withErrors('LOGO不合法');
+				}
+
+				$logoName = date('YmdHis').mt_rand(1000, 2000).'.'.$fileType;
+				$move = $file->move(base_path().'/public/upload/image/', $logoName);
+				$logo = $move? '/upload/image/'.$logoName : '';
+			}else{
+				$logo = '';
+			}
+
+			DB::beginTransaction();
+			try{
+				for($i = 0; $i < $request->num; $i++){
+					$obj = new Coupon();
+					$obj->name = $request->name;
+					$obj->sn = empty($request->sn)? strtoupper(makeRandStr(8)) : $request->sn;
+					$obj->logo = $logo;
+					$obj->type = $request->type;
+					$obj->usage = $request->usage;
+					$obj->amount = $request->type == 2? 0 : $request->amount;
+					$obj->discount = $request->type != 2? 0 : $request->discount;
+					$obj->available_start = strtotime(date('Y-m-d 00:00:00', strtotime($request->available_start)));
+					$obj->available_end = strtotime(date('Y-m-d 23:59:59', strtotime($request->available_end)));
+					$obj->status = 0;
+					$obj->save();
+				}
+
+				DB::commit();
+
+				return Redirect::back()->with('successMsg', '生成成功');
+			} catch(Exception $e){
+				DB::rollBack();
+
+				Log::error('生成优惠券失败:'.$e->getMessage());
+
+				return Redirect::back()->withInput()->withErrors('生成失败:'.$e->getMessage());
+			}
+		}else{
+			return Response::view('coupon.addCoupon');
+		}
+	}
+
+	// 删除优惠券
+	public function delCoupon(Request $request)
+	{
+		Coupon::query()->where('id', $request->input('id'))->delete();
+
+		return Response::json(['status' => 'success', 'data' => '', 'message' => '删除成功']);
+	}
+
+	// 导出卡券
+	public function exportCoupon(Request $request)
+	{
+		$cashCouponList = Coupon::type(1)->where('status', 0)->get();
+		$discountCouponList = Coupon::type(2)->where('status', 0)->get();
+		$chargeCouponList = Coupon::type(3)->where('status', 0)->get();
+
+		$filename = '卡券'.date('Ymd').'.xlsx';
+		$spreadsheet = new Spreadsheet();
+		$spreadsheet->getProperties()->setCreator('SSRPanel')->setLastModifiedBy('SSRPanel')->setTitle('邀请码')->setSubject('邀请码')->setDescription('')->setKeywords('')->setCategory('');
+
+		// 抵用券
+		$spreadsheet->setActiveSheetIndex(0);
+		$sheet = $spreadsheet->getActiveSheet();
+		$sheet->setTitle('抵用券');
+		$sheet->fromArray(['名称', '类型', '有效期', '券码', '金额(元)'], NULL);
+		foreach($cashCouponList as $k => $vo){
+			$usage = $vo->usage == 1? '一次性' : '重复使用';
+			$dateRange = date('Y-m-d', $vo->available_start).' ~ '.date('Y-m-d', $vo->available_end);
+			$sheet->fromArray([$vo->name, $usage, $dateRange, $vo->sn, $vo->amount], NULL, 'A'.($k+2));
+		}
+
+		// 折扣券
+		$spreadsheet->createSheet(1);
+		$spreadsheet->setActiveSheetIndex(1);
+		$sheet = $spreadsheet->getActiveSheet();
+		$sheet->setTitle('折扣券');
+		$sheet->fromArray(['名称', '类型', '有效期', '券码', '折扣(折)'], NULL);
+		foreach($discountCouponList as $k => $vo){
+			$usage = $vo->usage == 1? '一次性' : '重复使用';
+			$dateRange = date('Y-m-d', $vo->available_start).' ~ '.date('Y-m-d', $vo->available_end);
+			$sheet->fromArray([$vo->name, $usage, $dateRange, $vo->sn, $vo->discount], NULL, 'A'.($k+2));
+		}
+
+		// 充值券
+		$spreadsheet->createSheet(2);
+		$spreadsheet->setActiveSheetIndex(2);
+		$sheet = $spreadsheet->getActiveSheet();
+		$sheet->setTitle('充值券');
+		$sheet->fromArray(['名称', '类型', '有效期', '券码', '金额(元)'], NULL);
+		foreach($chargeCouponList as $k => $vo){
+			$usage = '一次性';
+			$dateRange = date('Y-m-d', $vo->available_start).' ~ '.date('Y-m-d', $vo->available_end);
+			$sheet->fromArray([$vo->name, $usage, $dateRange, $vo->sn, $vo->amount], NULL, 'A'.($k+2));
+		}
+
+		// 指针切换回第一个sheet
+		$spreadsheet->setActiveSheetIndex(0);
+
+		header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'); // 输出07Excel文件
+		//header('Content-Type:application/vnd.ms-excel'); // 输出Excel03版本文件
+		header('Content-Disposition: attachment;filename="'.$filename.'"');
+		header('Cache-Control: max-age=0');
+		$writer = new Xlsx($spreadsheet);
+		$writer->save('php://output');
+	}
 }

+ 64 - 64
app/Http/Controllers/MarketingController.php

@@ -20,91 +20,91 @@ use Response;
  */
 class MarketingController extends Controller
 {
-    protected static $systemConfig;
+	protected static $systemConfig;
 
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-    }
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+	}
 
-    // 邮件群发消息列表
-    public function emailList(Request $request)
-    {
-        $status = $request->input('status');
+	// 邮件群发消息列表
+	public function emailList(Request $request)
+	{
+		$status = $request->input('status');
 
-        $query = Marketing::query()->where('type', 1);
+		$query = Marketing::query()->where('type', 1);
 
-        if (isset($status)) {
-            $query->where('status', $status);
-        }
+		if(isset($status)){
+			$query->where('status', $status);
+		}
 
-        $view['list'] = $query->paginate(15)->appends($request->except('page'));
+		$view['list'] = $query->paginate(15)->appends($request->except('page'));
 
-        return Response::view('marketing.emailList', $view);
-    }
+		return Response::view('marketing.emailList', $view);
+	}
 
-    // 消息通道群发列表
-    public function pushList(Request $request)
-    {
-        $status = $request->input('status');
+	// 消息通道群发列表
+	public function pushList(Request $request)
+	{
+		$status = $request->input('status');
 
-        $query = Marketing::query()->where('type', 2);
+		$query = Marketing::query()->where('type', 2);
 
-        if (isset($status)) {
-            $query->where('status', $status);
-        }
+		if(isset($status)){
+			$query->where('status', $status);
+		}
 
-        $view['list'] = $query->paginate(15);
+		$view['list'] = $query->paginate(15);
 
-        return Response::view('marketing.pushList', $view);
-    }
+		return Response::view('marketing.pushList', $view);
+	}
 
-    // 添加推送消息
-    public function addPushMarketing(Request $request)
-    {
-        $title = trim($request->input('title'));
-        $content = $request->input('content');
+	// 添加推送消息
+	public function addPushMarketing(Request $request)
+	{
+		$title = trim($request->input('title'));
+		$content = $request->input('content');
 
-        if (!self::$systemConfig['is_push_bear']) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '推送失败:请先启用并配置PushBear']);
-        }
+		if(!self::$systemConfig['is_push_bear']){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '推送失败:请先启用并配置PushBear']);
+		}
 
-        DB::beginTransaction();
-        try {
-            $client = new Client();
-            $response = $client->request('GET', 'https://pushbear.ftqq.com/sub', ['query' => ['sendkey' => self::$systemConfig['push_bear_send_key'], 'text' => $title, 'desp' => $content]]);
+		DB::beginTransaction();
+		try{
+			$client = new Client();
+			$response = $client->request('GET', 'https://pushbear.ftqq.com/sub', ['query' => ['sendkey' => self::$systemConfig['push_bear_send_key'], 'text' => $title, 'desp' => $content]]);
 
-            $result = json_decode($response->getBody());
-            if ($result->code) { // 失败
-                $this->addMarketing(2, $title, $content, -1, $result->message);
+			$result = json_decode($response->getBody());
+			if($result->code){ // 失败
+				$this->addMarketing(2, $title, $content, -1, $result->message);
 
-                throw new Exception($result->message);
-            }
+				throw new Exception($result->message);
+			}
 
-            $this->addMarketing(2, $title, $content, 1);
+			$this->addMarketing(2, $title, $content, 1);
 
-            DB::commit();
+			DB::commit();
 
-            return Response::json(['status' => 'success', 'data' => '', 'message' => '推送成功']);
-        } catch (Exception $e) {
-            Log::info('PushBear消息推送失败:' . $e->getMessage());
+			return Response::json(['status' => 'success', 'data' => '', 'message' => '推送成功']);
+		} catch(Exception $e){
+			Log::info('PushBear消息推送失败:'.$e->getMessage());
 
-            DB::rollBack();
+			DB::rollBack();
 
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '推送失败:' . $e->getMessage()]);
-        }
-    }
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '推送失败:'.$e->getMessage()]);
+		}
+	}
 
-    private function addMarketing($type = 1, $title = '', $content = '', $status = 1, $error = '', $receiver = '')
-    {
-        $marketing = new Marketing();
-        $marketing->type = $type;
-        $marketing->receiver = $receiver;
-        $marketing->title = $title;
-        $marketing->content = $content;
-        $marketing->error = $error;
-        $marketing->status = $status;
+	private function addMarketing($type = 1, $title = '', $content = '', $status = 1, $error = '', $receiver = '')
+	{
+		$marketing = new Marketing();
+		$marketing->type = $type;
+		$marketing->receiver = $receiver;
+		$marketing->title = $title;
+		$marketing->content = $content;
+		$marketing->error = $error;
+		$marketing->status = $status;
 
-        return $marketing->save();
-    }
+		return $marketing->save();
+	}
 }

+ 228 - 228
app/Http/Controllers/PaymentController.php

@@ -28,232 +28,232 @@ use Validator;
  */
 class PaymentController extends Controller
 {
-    protected static $systemConfig;
-
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    // 创建支付单
-    public function create(Request $request)
-    {
-        $goods_id = $request->input('goods_id');
-        $coupon_sn = $request->input('coupon_sn');
-
-        $goods = Goods::query()->where('status', 1)->where('id', $goods_id)->first();
-        if (!$goods) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:商品或服务已下架']);
-        }
-
-        // 判断是否开启有赞云支付
-        if (!self::$systemConfig['is_youzan'] && !self::$systemConfig['is_alipay'] && !self::$systemConfig['is_f2fpay']) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:系统并未开启在线支付功能']);
-        }
-
-        // 判断是否存在同个商品的未支付订单
-        $existsOrder = Order::uid()->where('status', 0)->where('goods_id', $goods_id)->exists();
-        if ($existsOrder) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:尚有未支付的订单,请先去支付']);
-        }
-
-        // 限购控制
-        $strategy = self::$systemConfig['goods_purchase_limit_strategy'];
-        if ($strategy == 'all' || ($strategy == 'package' && $goods->type == 2) || ($strategy == 'free' && $goods->price == 0) || ($strategy == 'package&free' && ($goods->type == 2 || $goods->price == 0))) {
-            $noneExpireOrderExist = Order::uid()->where('status', '>=', 0)->where('is_expire', 0)->where('goods_id', $goods_id)->exists();
-            if ($noneExpireOrderExist) {
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:商品不可重复购买']);
-            }
-        }
-
-        // 单个商品限购
-        if ($goods->is_limit == 1) {
-            $noneExpireOrderExist = Order::uid()->where('status', '>=', 0)->where('goods_id', $goods_id)->exists();
-            if ($noneExpireOrderExist) {
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:此商品每人限购1次']);
-            }
-        }
-
-        // 使用优惠券
-        if ($coupon_sn) {
-            $coupon = Coupon::query()->where('status', 0)->whereIn('type', [1, 2])->where('sn', $coupon_sn)->first();
-            if (!$coupon) {
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:优惠券不存在']);
-            }
-
-            // 计算实际应支付总价
-            $amount = $coupon->type == 2 ? $goods->price * $coupon->discount / 10 : $goods->price - $coupon->amount;
-            $amount = $amount > 0 ? round($amount, 2) : 0; // 四舍五入保留2位小数,避免无法正常创建订单
-        } else {
-            $amount = $goods->price;
-        }
-
-        // 价格异常判断
-        if ($amount < 0) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:订单总价异常']);
-        } elseif ($amount == 0) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:订单总价为0,无需使用在线支付']);
-        }
-
-        // 验证账号是否存在有效期更长的套餐
-        if ($goods->type == 2) {
-            $existOrderList = Order::uid()->with(['goods'])->whereHas('goods', function ($q) {
-                $q->where('type', 2);
-            })->where('is_expire', 0)->where('status', 2)->get();
-
-            foreach ($existOrderList as $vo) {
-                if ($vo->goods->days > $goods->days) {
-                    return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:您已存在有效期更长的套餐,只能购买流量包']);
-                }
-            }
-        }
-
-        DB::beginTransaction();
-        try {
-            $orderSn = date('ymdHis') . mt_rand(100000, 999999);
-            $sn = makeRandStr(12);
-
-            // 支付方式
-            if (self::$systemConfig['is_youzan']) {
-                $pay_way = 2;
-            } elseif (self::$systemConfig['is_alipay']) {
-                $pay_way = 4;
-            } elseif (self::$systemConfig['is_f2fpay']) {
-                $pay_way = 5;
-            }
-
-            // 生成订单
-            $order = new Order();
-            $order->order_sn = $orderSn;
-            $order->user_id = Auth::user()->id;
-            $order->goods_id = $goods_id;
-            $order->coupon_id = !empty($coupon) ? $coupon->id : 0;
-            $order->origin_amount = $goods->price;
-            $order->amount = $amount;
-            $order->expire_at = date("Y-m-d H:i:s", strtotime("+" . $goods->days . " days"));
-            $order->is_expire = 0;
-            $order->pay_way = $pay_way;
-            $order->status = 0;
-            $order->save();
-
-            // 生成支付单
-            if (self::$systemConfig['is_youzan']) {
-                $yzy = new Yzy();
-                $result = $yzy->createQrCode($goods->name, $amount * 100, $orderSn);
-                if (isset($result['error_response'])) {
-                    Log::error('【有赞云】创建二维码失败:' . $result['error_response']['msg']);
-
-                    throw new Exception($result['error_response']['msg']);
-                }
-            } elseif (self::$systemConfig['is_alipay']) {
-                $parameter = ["service"      => "create_forex_trade", // WAP:create_forex_trade_wap ,即时到帐:create_forex_trade
-                              "partner"      => self::$systemConfig['alipay_partner'], "notify_url" => self::$systemConfig['website_url'] . "/api/alipay", // 异步回调接口
-                              "return_url"   => self::$systemConfig['website_url'], "out_trade_no" => $orderSn,  // 订单号
-                              "subject"      => "Package", // 订单名称
-                    //"total_fee"      => $amount, // 金额
-                              "rmb_fee"      => $amount,   // 使用RMB标价,不再使用总金额
-                              "body"         => "",        // 商品描述,可为空
-                              "currency"     => self::$systemConfig['alipay_currency'], // 结算币种
-                              "product_code" => "NEW_OVERSEAS_SELLER", "_input_charset" => "utf-8"];
-
-                // 建立请求
-                $alipaySubmit = new AlipaySubmit(self::$systemConfig['alipay_sign_type'], self::$systemConfig['alipay_partner'], self::$systemConfig['alipay_key'], self::$systemConfig['alipay_private_key']);
-                $result = $alipaySubmit->buildRequestForm($parameter, "post", "确认");
-            } elseif (self::$systemConfig['is_f2fpay']) {
-                // TODO:goods表里增加一个字段用于自定义商品付款时展示的商品名称,
-                // TODO:这里增加一个随机商品列表,根据goods的价格随机取值
-                $result = Charge::run("ali_qr", ['use_sandbox' => false, "partner" => self::$systemConfig['f2fpay_app_id'], 'app_id' => self::$systemConfig['f2fpay_app_id'], 'sign_type' => 'RSA2', 'ali_public_key' => self::$systemConfig['f2fpay_public_key'], 'rsa_private_key' => self::$systemConfig['f2fpay_private_key'], 'notify_url' => self::$systemConfig['website_url'] . "/api/f2fpay", // 异步回调接口
-                                                 'return_url'  => self::$systemConfig['website_url'], 'return_raw' => false], ['body' => '', 'subject' => self::$systemConfig['f2fpay_subject_name'], 'order_no' => $orderSn, 'amount' => $amount,]);
-            }
-
-            $payment = new Payment();
-            $payment->sn = $sn;
-            $payment->user_id = Auth::user()->id;
-            $payment->oid = $order->oid;
-            $payment->order_sn = $orderSn;
-            $payment->pay_way = 1;
-            $payment->amount = $amount;
-            if (self::$systemConfig['is_youzan']) {
-                $payment->qr_id = $result['response']['qr_id'];
-                $payment->qr_url = $result['response']['qr_url'];
-                $payment->qr_code = $result['response']['qr_code'];
-                $payment->qr_local_url = $this->base64ImageSaver($result['response']['qr_code']);
-            } elseif (self::$systemConfig['is_alipay']) {
-                $payment->qr_code = $result;
-            } elseif (self::$systemConfig['is_f2fpay']) {
-                $payment->qr_code = $result;
-                $payment->qr_url = 'http://qr.topscan.com/api.php?text=' . $result . '&bg=ffffff&fg=000000&pt=1c73bd&m=10&w=400&el=1&inpt=1eabfc&logo=https://t.alipayobjects.com/tfscom/T1Z5XfXdxmXXXXXXXX.png';
-                $payment->qr_local_url = $payment->qr_url;
-            }
-            $payment->status = 0;
-            $payment->save();
-
-            // 优惠券置为已使用
-            if (!empty($coupon)) {
-                if ($coupon->usage == 1) {
-                    $coupon->status = 1;
-                    $coupon->save();
-                }
-
-                Helpers::addCouponLog($coupon->id, $goods_id, $order->oid, '在线支付使用');
-            }
-
-            DB::commit();
-
-            if (self::$systemConfig['is_alipay']) { // Alipay返回支付信息
-                return Response::json(['status' => 'success', 'data' => $result, 'message' => '创建订单成功,正在转到付款页面,请稍后']);
-            } else {
-                return Response::json(['status' => 'success', 'data' => $sn, 'message' => '创建订单成功,正在转到付款页面,请稍后']);
-            }
-        } catch (Exception $e) {
-            DB::rollBack();
-
-            Log::error('创建支付订单失败:' . $e->getMessage());
-
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建订单失败:' . $e->getMessage()]);
-        }
-    }
-
-    // 支付单详情
-    public function detail(Request $request, $sn)
-    {
-        $view['payment'] = Payment::uid()->with(['order', 'order.goods'])->where('sn', $sn)->firstOrFail();
-
-        return Response::view('payment.detail', $view);
-    }
-
-    // 获取订单支付状态
-    public function getStatus(Request $request)
-    {
-        $validator = Validator::make($request->all(), ['sn' => 'required|exists:payment,sn'], ['sn.required' => '请求失败:缺少sn', 'sn.exists' => '支付失败:支付单不存在']);
-
-        if ($validator->fails()) {
-            return Response::json(['status' => 'error', 'data' => '', 'message' => $validator->getMessageBag()->first()]);
-        }
-
-        $payment = Payment::uid()->where('sn', $request->sn)->first();
-        if ($payment->status > 0) {
-            return Response::json(['status' => 'success', 'data' => '', 'message' => '支付成功']);
-        } elseif ($payment->status < 0) {
-            return Response::json(['status' => 'error', 'data' => '', 'message' => '订单超时未支付,已自动关闭']);
-        } else {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '等待支付']);
-        }
-    }
-
-    // 回调日志
-    public function callbackList(Request $request)
-    {
-        $status = $request->input('status', 0);
-
-        $query = PaymentCallback::query();
-
-        if (isset($status)) {
-            $query->where('status', $status);
-        }
-
-        $view['list'] = $query->orderBy('id', 'desc')->paginate(10)->appends($request->except('page'));
-
-        return Response::view('payment.callbackList', $view);
-    }
+	protected static $systemConfig;
+
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	// 创建支付单
+	public function create(Request $request)
+	{
+		$goods_id = $request->input('goods_id');
+		$coupon_sn = $request->input('coupon_sn');
+
+		$goods = Goods::query()->where('status', 1)->where('id', $goods_id)->first();
+		if(!$goods){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:商品或服务已下架']);
+		}
+
+		// 判断是否开启有赞云支付
+		if(!self::$systemConfig['is_youzan'] && !self::$systemConfig['is_alipay'] && !self::$systemConfig['is_f2fpay']){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:系统并未开启在线支付功能']);
+		}
+
+		// 判断是否存在同个商品的未支付订单
+		$existsOrder = Order::uid()->where('status', 0)->where('goods_id', $goods_id)->exists();
+		if($existsOrder){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:尚有未支付的订单,请先去支付']);
+		}
+
+		// 限购控制
+		$strategy = self::$systemConfig['goods_purchase_limit_strategy'];
+		if($strategy == 'all' || ($strategy == 'package' && $goods->type == 2) || ($strategy == 'free' && $goods->price == 0) || ($strategy == 'package&free' && ($goods->type == 2 || $goods->price == 0))){
+			$noneExpireOrderExist = Order::uid()->where('status', '>=', 0)->where('is_expire', 0)->where('goods_id', $goods_id)->exists();
+			if($noneExpireOrderExist){
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:商品不可重复购买']);
+			}
+		}
+
+		// 单个商品限购
+		if($goods->is_limit == 1){
+			$noneExpireOrderExist = Order::uid()->where('status', '>=', 0)->where('goods_id', $goods_id)->exists();
+			if($noneExpireOrderExist){
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:此商品每人限购1次']);
+			}
+		}
+
+		// 使用优惠券
+		if($coupon_sn){
+			$coupon = Coupon::query()->where('status', 0)->whereIn('type', [1, 2])->where('sn', $coupon_sn)->first();
+			if(!$coupon){
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:优惠券不存在']);
+			}
+
+			// 计算实际应支付总价
+			$amount = $coupon->type == 2? $goods->price*$coupon->discount/10 : $goods->price-$coupon->amount;
+			$amount = $amount > 0? round($amount, 2) : 0; // 四舍五入保留2位小数,避免无法正常创建订单
+		}else{
+			$amount = $goods->price;
+		}
+
+		// 价格异常判断
+		if($amount < 0){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:订单总价异常']);
+		}elseif($amount == 0){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:订单总价为0,无需使用在线支付']);
+		}
+
+		// 验证账号是否存在有效期更长的套餐
+		if($goods->type == 2){
+			$existOrderList = Order::uid()->with(['goods'])->whereHas('goods', function($q){
+				$q->where('type', 2);
+			})->where('is_expire', 0)->where('status', 2)->get();
+
+			foreach($existOrderList as $vo){
+				if($vo->goods->days > $goods->days){
+					return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:您已存在有效期更长的套餐,只能购买流量包']);
+				}
+			}
+		}
+
+		DB::beginTransaction();
+		try{
+			$orderSn = date('ymdHis').mt_rand(100000, 999999);
+			$sn = makeRandStr(12);
+
+			// 支付方式
+			if(self::$systemConfig['is_youzan']){
+				$pay_way = 2;
+			}elseif(self::$systemConfig['is_alipay']){
+				$pay_way = 4;
+			}elseif(self::$systemConfig['is_f2fpay']){
+				$pay_way = 5;
+			}
+
+			// 生成订单
+			$order = new Order();
+			$order->order_sn = $orderSn;
+			$order->user_id = Auth::user()->id;
+			$order->goods_id = $goods_id;
+			$order->coupon_id = !empty($coupon)? $coupon->id : 0;
+			$order->origin_amount = $goods->price;
+			$order->amount = $amount;
+			$order->expire_at = date("Y-m-d H:i:s", strtotime("+".$goods->days." days"));
+			$order->is_expire = 0;
+			$order->pay_way = $pay_way;
+			$order->status = 0;
+			$order->save();
+
+			// 生成支付单
+			if(self::$systemConfig['is_youzan']){
+				$yzy = new Yzy();
+				$result = $yzy->createQrCode($goods->name, $amount*100, $orderSn);
+				if(isset($result['error_response'])){
+					Log::error('【有赞云】创建二维码失败:'.$result['error_response']['msg']);
+
+					throw new Exception($result['error_response']['msg']);
+				}
+			}elseif(self::$systemConfig['is_alipay']){
+				$parameter = ["service"      => "create_forex_trade", // WAP:create_forex_trade_wap ,即时到帐:create_forex_trade
+				              "partner"      => self::$systemConfig['alipay_partner'], "notify_url" => self::$systemConfig['website_url']."/api/alipay", // 异步回调接口
+				              "return_url"   => self::$systemConfig['website_url'], "out_trade_no" => $orderSn,  // 订单号
+				              "subject"      => "Package", // 订单名称
+					//"total_fee"      => $amount, // 金额
+					          "rmb_fee"      => $amount,   // 使用RMB标价,不再使用总金额
+					          "body"         => "",        // 商品描述,可为空
+					          "currency"     => self::$systemConfig['alipay_currency'], // 结算币种
+					          "product_code" => "NEW_OVERSEAS_SELLER", "_input_charset" => "utf-8"];
+
+				// 建立请求
+				$alipaySubmit = new AlipaySubmit(self::$systemConfig['alipay_sign_type'], self::$systemConfig['alipay_partner'], self::$systemConfig['alipay_key'], self::$systemConfig['alipay_private_key']);
+				$result = $alipaySubmit->buildRequestForm($parameter, "post", "确认");
+			}elseif(self::$systemConfig['is_f2fpay']){
+				// TODO:goods表里增加一个字段用于自定义商品付款时展示的商品名称,
+				// TODO:这里增加一个随机商品列表,根据goods的价格随机取值
+				$result = Charge::run("ali_qr", ['use_sandbox' => FALSE, "partner" => self::$systemConfig['f2fpay_app_id'], 'app_id' => self::$systemConfig['f2fpay_app_id'], 'sign_type' => 'RSA2', 'ali_public_key' => self::$systemConfig['f2fpay_public_key'], 'rsa_private_key' => self::$systemConfig['f2fpay_private_key'], 'notify_url' => self::$systemConfig['website_url']."/api/f2fpay", // 异步回调接口
+				                                 'return_url'  => self::$systemConfig['website_url'], 'return_raw' => FALSE], ['body' => '', 'subject' => self::$systemConfig['f2fpay_subject_name'], 'order_no' => $orderSn, 'amount' => $amount,]);
+			}
+
+			$payment = new Payment();
+			$payment->sn = $sn;
+			$payment->user_id = Auth::user()->id;
+			$payment->oid = $order->oid;
+			$payment->order_sn = $orderSn;
+			$payment->pay_way = 1;
+			$payment->amount = $amount;
+			if(self::$systemConfig['is_youzan']){
+				$payment->qr_id = $result['response']['qr_id'];
+				$payment->qr_url = $result['response']['qr_url'];
+				$payment->qr_code = $result['response']['qr_code'];
+				$payment->qr_local_url = $this->base64ImageSaver($result['response']['qr_code']);
+			}elseif(self::$systemConfig['is_alipay']){
+				$payment->qr_code = $result;
+			}elseif(self::$systemConfig['is_f2fpay']){
+				$payment->qr_code = $result;
+				$payment->qr_url = 'http://qr.topscan.com/api.php?text='.$result.'&bg=ffffff&fg=000000&pt=1c73bd&m=10&w=400&el=1&inpt=1eabfc&logo=https://t.alipayobjects.com/tfscom/T1Z5XfXdxmXXXXXXXX.png';
+				$payment->qr_local_url = $payment->qr_url;
+			}
+			$payment->status = 0;
+			$payment->save();
+
+			// 优惠券置为已使用
+			if(!empty($coupon)){
+				if($coupon->usage == 1){
+					$coupon->status = 1;
+					$coupon->save();
+				}
+
+				Helpers::addCouponLog($coupon->id, $goods_id, $order->oid, '在线支付使用');
+			}
+
+			DB::commit();
+
+			if(self::$systemConfig['is_alipay']){ // Alipay返回支付信息
+				return Response::json(['status' => 'success', 'data' => $result, 'message' => '创建订单成功,正在转到付款页面,请稍后']);
+			}else{
+				return Response::json(['status' => 'success', 'data' => $sn, 'message' => '创建订单成功,正在转到付款页面,请稍后']);
+			}
+		} catch(Exception $e){
+			DB::rollBack();
+
+			Log::error('创建支付订单失败:'.$e->getMessage());
+
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建订单失败:'.$e->getMessage()]);
+		}
+	}
+
+	// 支付单详情
+	public function detail(Request $request, $sn)
+	{
+		$view['payment'] = Payment::uid()->with(['order', 'order.goods'])->where('sn', $sn)->firstOrFail();
+
+		return Response::view('payment.detail', $view);
+	}
+
+	// 获取订单支付状态
+	public function getStatus(Request $request)
+	{
+		$validator = Validator::make($request->all(), ['sn' => 'required|exists:payment,sn'], ['sn.required' => '请求失败:缺少sn', 'sn.exists' => '支付失败:支付单不存在']);
+
+		if($validator->fails()){
+			return Response::json(['status' => 'error', 'data' => '', 'message' => $validator->getMessageBag()->first()]);
+		}
+
+		$payment = Payment::uid()->where('sn', $request->sn)->first();
+		if($payment->status > 0){
+			return Response::json(['status' => 'success', 'data' => '', 'message' => '支付成功']);
+		}elseif($payment->status < 0){
+			return Response::json(['status' => 'error', 'data' => '', 'message' => '订单超时未支付,已自动关闭']);
+		}else{
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '等待支付']);
+		}
+	}
+
+	// 回调日志
+	public function callbackList(Request $request)
+	{
+		$status = $request->input('status', 0);
+
+		$query = PaymentCallback::query();
+
+		if(isset($status)){
+			$query->where('status', $status);
+		}
+
+		$view['list'] = $query->orderBy('id', 'desc')->paginate(10)->appends($request->except('page'));
+
+		return Response::view('payment.callbackList', $view);
+	}
 }

+ 42 - 42
app/Http/Controllers/SensitiveWordsController.php

@@ -16,47 +16,47 @@ use Validator;
  */
 class SensitiveWordsController extends Controller
 {
-    // 敏感词列表
-    public function sensitiveWordsList(Request $request)
-    {
-        $view['list'] = SensitiveWords::query()->orderBy('id', 'desc')->paginate(15);
-
-        return Response::view('sensitiveWords.sensitiveWordsList', $view);
-    }
-
-    // 添加敏感词
-    public function addSensitiveWords(Request $request)
-    {
-        $validator = Validator::make($request->all(), [
-            'words' => 'required|unique:sensitive_words'
-        ], [
-            'words.required' => '添加失败:请填写敏感词',
-            'words.unique'   => '添加失败:敏感词已存在'
-        ]);
-
-        if ($validator->fails()) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => $validator->getMessageBag()->first()]);
-        }
-
-        $obj = new SensitiveWords();
-        $obj->words = strtolower($request->words);
-        $obj->save();
-        if ($obj->id) {
-            return Response::json(['status' => 'success', 'data' => '', 'message' => '添加成功']);
-        } else {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '添加失败']);
-        }
-    }
-
-    // 删除敏感词
-    public function delSensitiveWords(Request $request)
-    {
-        $result = SensitiveWords::query()->where('id', $request->id)->delete();
-        if ($result) {
-            return Response::json(['status' => 'success', 'data' => '', 'message' => '删除成功']);
-        } else {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '删除失败']);
-        }
-    }
+	// 敏感词列表
+	public function sensitiveWordsList(Request $request)
+	{
+		$view['list'] = SensitiveWords::query()->orderBy('id', 'desc')->paginate(15);
+
+		return Response::view('sensitiveWords.sensitiveWordsList', $view);
+	}
+
+	// 添加敏感词
+	public function addSensitiveWords(Request $request)
+	{
+		$validator = Validator::make($request->all(), [
+			'words' => 'required|unique:sensitive_words'
+		], [
+			'words.required' => '添加失败:请填写敏感词',
+			'words.unique'   => '添加失败:敏感词已存在'
+		]);
+
+		if($validator->fails()){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => $validator->getMessageBag()->first()]);
+		}
+
+		$obj = new SensitiveWords();
+		$obj->words = strtolower($request->words);
+		$obj->save();
+		if($obj->id){
+			return Response::json(['status' => 'success', 'data' => '', 'message' => '添加成功']);
+		}else{
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '添加失败']);
+		}
+	}
+
+	// 删除敏感词
+	public function delSensitiveWords(Request $request)
+	{
+		$result = SensitiveWords::query()->where('id', $request->id)->delete();
+		if($result){
+			return Response::json(['status' => 'success', 'data' => '', 'message' => '删除成功']);
+		}else{
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '删除失败']);
+		}
+	}
 
 }

+ 213 - 213
app/Http/Controllers/ShopController.php

@@ -22,217 +22,217 @@ use Session;
  */
 class ShopController extends Controller
 {
-    // 商品列表
-    public function goodsList(Request $request)
-    {
-        $type = $request->input('type');
-        $status = $request->input('status');
-
-        $query = Goods::query();
-
-        if (isset($type)) {
-            $query->where('type', $type);
-        }
-
-        if (isset($status)) {
-            $query->where('status', $status);
-        }
-
-        $view['goodsList'] = $query->orderBy('id', 'desc')->paginate(10)->appends($request->except('page'));
-
-        return Response::view('shop.goodsList', $view);
-    }
-
-    // 添加商品
-    public function addGoods(Request $request)
-    {
-        if ($request->isMethod('POST')) {
-            $this->validate($request, ['name' => 'required', 'traffic' => 'required_unless:type,3|integer|min:1024|max:10240000|nullable', 'price' => 'required|numeric|min:0', 'type' => 'required', 'days' => 'required|integer',], ['name.required' => '请填入名称', 'traffic.required_unless' => '请填入流量', 'traffic.integer' => '内含流量必须是整数值', 'traffic.min' => '内含流量不能低于1MB', 'traffic.max' => '内含流量不能超过10TB', 'price.required' => '请填入价格', 'price.numeric' => '价格不合法', 'price.min' => '价格最低0', 'type.required' => '请选择类型', 'days.required' => '请填入有效期', 'days.integer' => '有效期不合法',]);
-
-            // 套餐必须有价格
-            if ($request->type == 2 && $request->price <= 0) {
-                return Redirect::back()->withInput()->withErrors('套餐价格必须大于0');
-            }
-
-            // 套餐有效天数必须大于30天
-            if ($request->type == 2 && $request->days < 1) {
-                return Redirect::back()->withInput()->withErrors('套餐有效天数必须不能少于1天');
-            }
-
-            // 商品LOGO
-            if ($request->hasFile('logo')) {
-                $file = $request->file('logo');
-                $fileType = $file->getClientOriginalExtension();
-
-                // 验证文件合法性
-                if (!in_array($fileType, ['jpg', 'png', 'jpeg', 'bmp'])) {
-                    return Redirect::back()->withInput()->withErrors('LOGO不合法');
-                }
-
-                $logoName = date('YmdHis') . mt_rand(1000, 2000) . '.' . $fileType;
-                $move = $file->move(base_path() . '/public/upload/image/', $logoName);
-                $logo = $move ? '/upload/image/' . $logoName : '';
-            } else {
-                $logo = '';
-            }
-
-            DB::beginTransaction();
-            try {
-                $goods = new Goods();
-                $goods->name = $request->name;
-                $goods->info = $request->info;
-                $goods->desc = $request->desc;
-                $goods->logo = $logo;
-                $goods->traffic = $request->traffic;
-                $goods->price = round($request->price, 2);
-                $goods->type = $request->type;
-                $goods->days = $request->days;
-                $goods->color = $request->color;
-                $goods->sort = $request->sort;
-                $goods->is_hot = $request->is_hot;
-                $goods->is_limit = $request->is_limit;
-                $goods->status = $request->status;
-                $goods->save();
-
-                // 生成SKU
-                $goods->sku = 'S0000' . $goods->id;
-                $goods->save();
-
-                // 生成商品标签
-                $labels = $request->input('labels');
-                if (!empty($labels)) {
-                    foreach ($labels as $label) {
-                        $goodsLabel = new GoodsLabel();
-                        $goodsLabel->goods_id = $goods->id;
-                        $goodsLabel->label_id = $label;
-                        $goodsLabel->save();
-                    }
-                }
-
-                DB::commit();
-
-                return Redirect::back()->with('successMsg', '添加成功');
-            } catch (Exception $e) {
-                DB::rollBack();
-                Log::info($e);
-
-                return Redirect::back()->withInput()->withErrors('添加失败');
-            }
-        } else {
-            $view['label_list'] = Label::query()->orderBy('sort', 'desc')->orderBy('id', 'asc')->get();
-
-            return Response::view('shop.addGoods', $view);
-        }
-    }
-
-    // 编辑商品
-    public function editGoods(Request $request, $id)
-    {
-        if ($request->isMethod('POST')) {
-            $name = $request->input('name');
-            $info = $request->input('info');
-            $desc = $request->input('desc');
-            $price = round($request->input('price'), 2);
-            $labels = $request->input('labels');
-            $color = $request->input('color');
-            $sort = $request->input('sort');
-            $is_hot = $request->input('is_hot');
-            $is_limit = $request->input('is_limit');
-            $status = $request->input('status');
-
-            $goods = Goods::query()->where('id', $id)->first();
-            if (!$goods) {
-                Session::flash('errorMsg', '商品不存在');
-
-                return Redirect::back();
-            }
-
-            if (empty($name)) {
-                Session::flash('errorMsg', '请填写完整');
-
-                return Redirect::back()->withInput();
-            }
-
-            // 套餐必须有价格
-            if ($goods->type == 2 && $price <= 0) {
-                Session::flash('errorMsg', '套餐价格必须大于0');
-
-                return Redirect::back()->withInput();
-            }
-
-            // 商品LOGO
-            $logo = '';
-            if ($request->hasFile('logo')) {
-                $file = $request->file('logo');
-                $fileType = $file->getClientOriginalExtension();
-
-                // 验证文件合法性
-                if (!in_array($fileType, ['jpg', 'png', 'jpeg', 'bmp'])) {
-                    Session::flash('errorMsg', 'LOGO不合法');
-
-                    return Redirect::back()->withInput();
-                }
-
-                $logoName = date('YmdHis') . mt_rand(1000, 2000) . '.' . $fileType;
-                $move = $file->move(base_path() . '/public/upload/image/', $logoName);
-                $logo = $move ? '/upload/image/' . $logoName : '';
-            }
-
-            DB::beginTransaction();
-            try {
-                $data = ['name' => $name, 'info' => $info, 'desc' => $desc, 'price' => $price * 100, 'sort' => $sort, 'color' => $color, 'is_hot' => $is_hot, 'is_limit' => $is_limit, 'status' => $status];
-
-                if ($logo) {
-                    $data['logo'] = $logo;
-                }
-
-                Goods::query()->where('id', $id)->update($data);
-
-                // 先删除该商品所有的标签
-                GoodsLabel::query()->where('goods_id', $id)->delete();
-
-                // 生成商品标签
-                if (!empty($labels)) {
-                    foreach ($labels as $label) {
-                        $goodsLabel = new GoodsLabel();
-                        $goodsLabel->goods_id = $id;
-                        $goodsLabel->label_id = $label;
-                        $goodsLabel->save();
-                    }
-                }
-
-                Session::flash('successMsg', '编辑成功');
-
-                DB::commit();
-            } catch (Exception $e) {
-                Session::flash('errorMsg', '编辑失败');
-
-                DB::rollBack();
-            }
-
-            return Redirect::to('shop/editGoods/' . $id);
-        } else {
-            $goods = Goods::query()->with(['label'])->where('id', $id)->first();
-            if ($goods) {
-                $label = [];
-                foreach ($goods->label as $vo) {
-                    $label[] = $vo->label_id;
-                }
-                $goods->labels = $label;
-            }
-
-            $view['goods'] = $goods;
-            $view['label_list'] = Label::query()->orderBy('sort', 'desc')->orderBy('id', 'asc')->get();
-
-            return Response::view('shop.editGoods', $view);
-        }
-    }
-
-    // 删除商品
-    public function delGoods(Request $request)
-    {
-        Goods::query()->where('id', $request->input('id'))->delete();
-
-        return Response::json(['status' => 'success', 'data' => '', 'message' => '删除成功']);
-    }
+	// 商品列表
+	public function goodsList(Request $request)
+	{
+		$type = $request->input('type');
+		$status = $request->input('status');
+
+		$query = Goods::query();
+
+		if(isset($type)){
+			$query->where('type', $type);
+		}
+
+		if(isset($status)){
+			$query->where('status', $status);
+		}
+
+		$view['goodsList'] = $query->orderBy('status', 'desc')->paginate(10)->appends($request->except('page'));
+
+		return Response::view('shop.goodsList', $view);
+	}
+
+	// 添加商品
+	public function addGoods(Request $request)
+	{
+		if($request->isMethod('POST')){
+			$this->validate($request, ['name' => 'required', 'traffic' => 'required_unless:type,3|integer|min:1024|max:10240000|nullable', 'price' => 'required|numeric|min:0', 'type' => 'required', 'days' => 'required|integer',], ['name.required' => '请填入名称', 'traffic.required_unless' => '请填入流量', 'traffic.integer' => '内含流量必须是整数值', 'traffic.min' => '内含流量不能低于1MB', 'traffic.max' => '内含流量不能超过10TB', 'price.required' => '请填入价格', 'price.numeric' => '价格不合法', 'price.min' => '价格最低0', 'type.required' => '请选择类型', 'days.required' => '请填入有效期', 'days.integer' => '有效期不合法',]);
+
+			// 套餐必须有价格
+			if($request->type == 2 && $request->price <= 0){
+				return Redirect::back()->withInput()->withErrors('套餐价格必须大于0');
+			}
+
+			// 套餐有效天数必须大于30天
+			if($request->type == 2 && $request->days < 1){
+				return Redirect::back()->withInput()->withErrors('套餐有效天数必须不能少于1天');
+			}
+
+			// 商品LOGO
+			if($request->hasFile('logo')){
+				$file = $request->file('logo');
+				$fileType = $file->getClientOriginalExtension();
+
+				// 验证文件合法性
+				if(!in_array($fileType, ['jpg', 'png', 'jpeg', 'bmp'])){
+					return Redirect::back()->withInput()->withErrors('LOGO不合法');
+				}
+
+				$logoName = date('YmdHis').mt_rand(1000, 2000).'.'.$fileType;
+				$move = $file->move(base_path().'/public/upload/image/', $logoName);
+				$logo = $move? '/upload/image/'.$logoName : '';
+			}else{
+				$logo = '';
+			}
+
+			DB::beginTransaction();
+			try{
+				$goods = new Goods();
+				$goods->name = $request->name;
+				$goods->info = $request->info;
+				$goods->desc = $request->desc;
+				$goods->logo = $logo;
+				$goods->traffic = $request->traffic;
+				$goods->price = round($request->price, 2);
+				$goods->type = $request->type;
+				$goods->days = $request->days;
+				$goods->color = $request->color;
+				$goods->sort = $request->sort;
+				$goods->is_hot = $request->is_hot;
+				$goods->is_limit = $request->is_limit;
+				$goods->status = $request->status;
+				$goods->save();
+
+				// 生成SKU
+				$goods->sku = 'S0000'.$goods->id;
+				$goods->save();
+
+				// 生成商品标签
+				$labels = $request->input('labels');
+				if(!empty($labels)){
+					foreach($labels as $label){
+						$goodsLabel = new GoodsLabel();
+						$goodsLabel->goods_id = $goods->id;
+						$goodsLabel->label_id = $label;
+						$goodsLabel->save();
+					}
+				}
+
+				DB::commit();
+
+				return Redirect::back()->with('successMsg', '添加成功');
+			} catch(Exception $e){
+				DB::rollBack();
+				Log::info($e);
+
+				return Redirect::back()->withInput()->withErrors('添加失败');
+			}
+		}else{
+			$view['label_list'] = Label::query()->orderBy('sort', 'desc')->orderBy('id', 'asc')->get();
+
+			return Response::view('shop.addGoods', $view);
+		}
+	}
+
+	// 编辑商品
+	public function editGoods(Request $request, $id)
+	{
+		if($request->isMethod('POST')){
+			$name = $request->input('name');
+			$info = $request->input('info');
+			$desc = $request->input('desc');
+			$price = round($request->input('price'), 2);
+			$labels = $request->input('labels');
+			$color = $request->input('color');
+			$sort = $request->input('sort');
+			$is_hot = $request->input('is_hot');
+			$is_limit = $request->input('is_limit');
+			$status = $request->input('status');
+
+			$goods = Goods::query()->where('id', $id)->first();
+			if(!$goods){
+				Session::flash('errorMsg', '商品不存在');
+
+				return Redirect::back();
+			}
+
+			if(empty($name)){
+				Session::flash('errorMsg', '请填写完整');
+
+				return Redirect::back()->withInput();
+			}
+
+			// 套餐必须有价格
+			if($goods->type == 2 && $price <= 0){
+				Session::flash('errorMsg', '套餐价格必须大于0');
+
+				return Redirect::back()->withInput();
+			}
+
+			// 商品LOGO
+			$logo = '';
+			if($request->hasFile('logo')){
+				$file = $request->file('logo');
+				$fileType = $file->getClientOriginalExtension();
+
+				// 验证文件合法性
+				if(!in_array($fileType, ['jpg', 'png', 'jpeg', 'bmp'])){
+					Session::flash('errorMsg', 'LOGO不合法');
+
+					return Redirect::back()->withInput();
+				}
+
+				$logoName = date('YmdHis').mt_rand(1000, 2000).'.'.$fileType;
+				$move = $file->move(base_path().'/public/upload/image/', $logoName);
+				$logo = $move? '/upload/image/'.$logoName : '';
+			}
+
+			DB::beginTransaction();
+			try{
+				$data = ['name' => $name, 'info' => $info, 'desc' => $desc, 'price' => $price*100, 'sort' => $sort, 'color' => $color, 'is_hot' => $is_hot, 'is_limit' => $is_limit, 'status' => $status];
+
+				if($logo){
+					$data['logo'] = $logo;
+				}
+
+				Goods::query()->where('id', $id)->update($data);
+
+				// 先删除该商品所有的标签
+				GoodsLabel::query()->where('goods_id', $id)->delete();
+
+				// 生成商品标签
+				if(!empty($labels)){
+					foreach($labels as $label){
+						$goodsLabel = new GoodsLabel();
+						$goodsLabel->goods_id = $id;
+						$goodsLabel->label_id = $label;
+						$goodsLabel->save();
+					}
+				}
+
+				Session::flash('successMsg', '编辑成功');
+
+				DB::commit();
+			} catch(Exception $e){
+				Session::flash('errorMsg', '编辑失败');
+
+				DB::rollBack();
+			}
+
+			return Redirect::to('shop/editGoods/'.$id);
+		}else{
+			$goods = Goods::query()->with(['label'])->where('id', $id)->first();
+			if($goods){
+				$label = [];
+				foreach($goods->label as $vo){
+					$label[] = $vo->label_id;
+				}
+				$goods->labels = $label;
+			}
+
+			$view['goods'] = $goods;
+			$view['label_list'] = Label::query()->orderBy('sort', 'desc')->orderBy('id', 'asc')->get();
+
+			return Response::view('shop.editGoods', $view);
+		}
+	}
+
+	// 删除商品
+	public function delGoods(Request $request)
+	{
+		Goods::query()->where('id', $request->input('id'))->delete();
+
+		return Response::json(['status' => 'success', 'data' => '', 'message' => '删除成功']);
+	}
 }

+ 257 - 257
app/Http/Controllers/SubscribeController.php

@@ -23,263 +23,263 @@ use Response;
  */
 class SubscribeController extends Controller
 {
-    protected static $systemConfig;
+	protected static $systemConfig;
 
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-    }
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+	}
 
-    // 订阅码列表
-    public function subscribeList(Request $request)
-    {
-        $user_id = $request->input('user_id');
-        $username = $request->input('username');
-        $status = $request->input('status');
-
-        $query = UserSubscribe::with(['User']);
-
-        if (isset($user_id)) {
-            $query->where('user_id', $user_id);
-        }
-
-        if (isset($username)) {
-            $query->whereHas('user', function ($q) use ($username) {
-                $q->where('username', 'like', '%' . $username . '%');
-            });
-        }
-
-        if (isset($status)) {
-            $query->where('status', $status);
-        }
-
-        $view['subscribeList'] = $query->orderBy('id', 'desc')->paginate(20)->appends($request->except('page'));
-
-        return Response::view('subscribe.subscribeList', $view);
-    }
-
-    // 订阅设备列表
-    public function deviceList(Request $request)
-    {
-        $type = $request->input('type');
-        $platform = $request->input('platform');
-        $name = $request->input('name');
-        $status = $request->input('status');
-
-        $query = Device::query();
-
-        if (isset($type)) {
-            $query->where('type', $type);
-        }
-
-        if (isset($platform)) {
-            $query->where('platform', $platform);
-        }
-
-        if (isset($name)) {
-            $query->where('name', 'like', '%' . $name . '%');
-        }
-
-        if (isset($status)) {
-            $query->where('status', $status);
-        }
-
-        $view['deviceList'] = $query->paginate(20)->appends($request->except('page'));
-
-        return Response::view('subscribe.deviceList', $view);
-    }
-
-    // 设置用户的订阅的状态
-    public function setSubscribeStatus(Request $request)
-    {
-        $id = $request->input('id');
-        $status = $request->input('status', 0);
-
-        if (empty($id)) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '操作异常']);
-        }
-
-        if ($status) {
-            UserSubscribe::query()->where('id', $id)->update(['status' => 1, 'ban_time' => 0, 'ban_desc' => '']);
-        } else {
-            UserSubscribe::query()->where('id', $id)->update(['status' => 0, 'ban_time' => time(), 'ban_desc' => '后台手动封禁']);
-        }
-
-        return Response::json(['status' => 'success', 'data' => '', 'message' => '操作成功']);
-    }
-
-    // 设置设备是否允许订阅的状态
-    public function setDeviceStatus(Request $request)
-    {
-        $id = $request->input('id');
-        $status = $request->input('status', 0);
-
-        if (empty($id)) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '操作异常']);
-        }
-
-        Device::query()->where('id', $id)->update(['status' => $status]);
-
-        return Response::json(['status' => 'success', 'data' => '', 'message' => '操作成功']);
-    }
-
-    // 通过订阅码获取订阅信息
-    public function getSubscribeByCode(Request $request, $code)
-    {
-        if (empty($code)) {
-            return Redirect::to('login');
-        }
-
-        // 校验合法性
-        $subscribe = UserSubscribe::query()->with('user')->where('status', 1)->where('code', $code)->first();
-        if (!$subscribe) {
-            exit($this->noneNode());
-        }
-
-        $user = User::query()->whereIn('status', [0, 1])->where('enable', 1)->where('id', $subscribe->user_id)->first();
-        if (!$user) {
-            exit($this->noneNode());
-        }
-
-        // 更新访问次数
-        $subscribe->increment('times', 1);
-
-        // 记录每次请求
-        $this->log($subscribe->id, getClientIp(), $request->headers);
-
-        // 获取这个账号可用节点
-        $userLabelIds = UserLabel::query()->where('user_id', $user->id)->pluck('label_id');
-        if (empty($userLabelIds)) {
-            exit($this->noneNode());
-        }
-
-        $query = SsNode::query()->selectRaw('ss_node.*')->leftjoin("ss_node_label", "ss_node.id", "=", "ss_node_label.node_id");
-
-        // 启用混合订阅时,加入V2Ray节点,未启用时仅下发SSR节点信息
-        if (!self::$systemConfig['mix_subscribe']) {
-            $query->where('ss_node.type', 1);
-        }
-
-        $nodeList = $query->where('ss_node.status', 1)->where('ss_node.is_subscribe', 1)->whereIn('ss_node_label.label_id', $userLabelIds)->groupBy('ss_node.id')->orderBy('ss_node.sort', 'desc')->orderBy('ss_node.id', 'asc')->get()->toArray();
-        if (empty($nodeList)) {
-            exit($this->noneNode());
-        }
-
-        // 打乱数组
-        if (self::$systemConfig['rand_subscribe']) {
-            shuffle($nodeList);
-        }
-
-        // 控制客户端最多获取节点数
-        $scheme = '';
-
-        // 展示到期时间和剩余流量
-        if (self::$systemConfig['is_custom_subscribe']) {
-            $scheme .= $this->expireDate($user);
-            $scheme .= $this->lastTraffic($user);
-        }
-
-        foreach ($nodeList as $key => $node) {
-            // 控制显示的节点数
-            if (self::$systemConfig['subscribe_max'] && $key >= self::$systemConfig['subscribe_max']) {
-                break;
-            }
-
-            // 获取分组名称
-            if ($node['type'] == 1) {
-                $group = SsGroup::query()->where('id', $node['group_id'])->first();
-
-                $obfs_param = $user->obfs_param ? $user->obfs_param : $node['obfs_param'];
-                $protocol_param = $node['single'] ? $user->port . ':' . $user->passwd : $user->protocol_param;
-
-                // 生成ssr scheme
-                $ssr_str = ($node['server'] ? $node['server'] : $node['ip']) . ':' . ($node['single'] ? $node['single_port'] : $user->port);
-                $ssr_str .= ':' . ($node['single'] ? $node['single_protocol'] : $user->protocol) . ':' . ($node['single'] ? $node['single_method'] : $user->method);
-                $ssr_str .= ':' . ($node['single'] ? $node['single_obfs'] : $user->obfs) . ':' . ($node['single'] ? base64url_encode($node['single_passwd']) : base64url_encode($user->passwd));
-                $ssr_str .= '/?obfsparam=' . base64url_encode($obfs_param);
-                $ssr_str .= '&protoparam=' . ($node['single'] ? base64url_encode($user->port . ':' . $user->passwd) : base64url_encode($protocol_param));
-                $ssr_str .= '&remarks=' . base64url_encode($node['name']);
-                $ssr_str .= '&group=' . base64url_encode(empty($group) ? Helpers::systemConfig()['website_name'] : $group->name);
-                $ssr_str .= '&udpport=0';
-                $ssr_str .= '&uot=0';
-                $ssr_str = base64url_encode($ssr_str);
-                $scheme .= 'ssr://' . $ssr_str . "\n";
-            } else {
-                // 生成v2ray scheme
-                $v2_json = [
-                    "v"    => "2",
-                    "ps"   => $node['name'],
-                    "add"  => $node['server'] ? $node['server'] : $node['ip'],
-                    "port" => $node['v2_port'],
-                    "id"   => $user->vmess_id,
-                    "aid"  => $node['v2_alter_id'],
-                    "net"  => $node['v2_net'],
-                    "type" => $node['v2_type'],
-                    "host" => $node['v2_host'],
-                    "path" => $node['v2_path'],
-                    "tls"  => $node['v2_tls'] ? "tls" : ""
-                ];
-
-                $scheme .= 'vmess://' . base64url_encode(json_encode($v2_json, JSON_PRETTY_PRINT)) . "\n";
-            }
-        }
-
-        // 适配Quantumult的自定义订阅头
-        if (self::$systemConfig['is_custom_subscribe']) {
-            $headers = [
-                'Content-type'          => 'application/octet-stream; charset=utf-8',
-                'Cache-Control'         => 'no-store, no-cache, must-revalidate',
-                'Subscription-Userinfo' => 'upload=' . $user->u . '; download=' . $user->d . '; total=' . $user->transfer_enable . '; expire=' . strtotime($user->expire_time)
-            ];
-
-            return Response::make(base64url_encode($scheme), 200, $headers);
-        } else {
-            return Response::make(base64url_encode($scheme));
-        }
-    }
-
-    // 写入订阅访问日志
-    private function log($subscribeId, $ip, $headers)
-    {
-        $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();
-    }
-
-    // 抛出无可用的节点信息,用于兼容防止客户端订阅失败
-    private function noneNode()
-    {
-        return base64url_encode('ssr://' . base64url_encode('0.0.0.0:1:origin:none:plain:' . base64url_encode('0000') . '/?obfsparam=&protoparam=&remarks=' . base64url_encode('无可用节点或账号被封禁或订阅被封禁') . '&group=' . base64url_encode('错误') . '&udpport=0&uot=0') . "\n");
-    }
-
-    /**
-     * 过期时间
-     *
-     * @param object $user
-     *
-     * @return string
-     */
-    private function expireDate($user)
-    {
-        $text = '到期时间:' . $user->expire_time;
-
-        return 'ssr://' . base64url_encode('0.0.0.1:1:origin:none:plain:' . base64url_encode('0000') . '/?obfsparam=&protoparam=&remarks=' . base64url_encode($text) . '&group=' . base64url_encode(Helpers::systemConfig()['website_name']) . '&udpport=0&uot=0') . "\n";
-    }
-
-    /**
-     * 剩余流量
-     *
-     * @param object $user
-     *
-     * @return string
-     */
-    private function lastTraffic($user)
-    {
-        $text = '剩余流量:' . flowAutoShow($user->transfer_enable - $user->u - $user->d);
-
-        return 'ssr://' . base64url_encode('0.0.0.2:1:origin:none:plain:' . base64url_encode('0000') . '/?obfsparam=&protoparam=&remarks=' . base64url_encode($text) . '&group=' . base64url_encode(Helpers::systemConfig()['website_name']) . '&udpport=0&uot=0') . "\n";
-    }
+	// 订阅码列表
+	public function subscribeList(Request $request)
+	{
+		$user_id = $request->input('user_id');
+		$username = $request->input('username');
+		$status = $request->input('status');
+
+		$query = UserSubscribe::with(['User']);
+
+		if(isset($user_id)){
+			$query->where('user_id', $user_id);
+		}
+
+		if(isset($username)){
+			$query->whereHas('user', function($q) use ($username){
+				$q->where('username', 'like', '%'.$username.'%');
+			});
+		}
+
+		if(isset($status)){
+			$query->where('status', $status);
+		}
+
+		$view['subscribeList'] = $query->orderBy('id', 'desc')->paginate(20)->appends($request->except('page'));
+
+		return Response::view('subscribe.subscribeList', $view);
+	}
+
+	// 订阅设备列表
+	public function deviceList(Request $request)
+	{
+		$type = $request->input('type');
+		$platform = $request->input('platform');
+		$name = $request->input('name');
+		$status = $request->input('status');
+
+		$query = Device::query();
+
+		if(isset($type)){
+			$query->where('type', $type);
+		}
+
+		if(isset($platform)){
+			$query->where('platform', $platform);
+		}
+
+		if(isset($name)){
+			$query->where('name', 'like', '%'.$name.'%');
+		}
+
+		if(isset($status)){
+			$query->where('status', $status);
+		}
+
+		$view['deviceList'] = $query->paginate(20)->appends($request->except('page'));
+
+		return Response::view('subscribe.deviceList', $view);
+	}
+
+	// 设置用户的订阅的状态
+	public function setSubscribeStatus(Request $request)
+	{
+		$id = $request->input('id');
+		$status = $request->input('status', 0);
+
+		if(empty($id)){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '操作异常']);
+		}
+
+		if($status){
+			UserSubscribe::query()->where('id', $id)->update(['status' => 1, 'ban_time' => 0, 'ban_desc' => '']);
+		}else{
+			UserSubscribe::query()->where('id', $id)->update(['status' => 0, 'ban_time' => time(), 'ban_desc' => '后台手动封禁']);
+		}
+
+		return Response::json(['status' => 'success', 'data' => '', 'message' => '操作成功']);
+	}
+
+	// 设置设备是否允许订阅的状态
+	public function setDeviceStatus(Request $request)
+	{
+		$id = $request->input('id');
+		$status = $request->input('status', 0);
+
+		if(empty($id)){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '操作异常']);
+		}
+
+		Device::query()->where('id', $id)->update(['status' => $status]);
+
+		return Response::json(['status' => 'success', 'data' => '', 'message' => '操作成功']);
+	}
+
+	// 通过订阅码获取订阅信息
+	public function getSubscribeByCode(Request $request, $code)
+	{
+		if(empty($code)){
+			return Redirect::to('login');
+		}
+
+		// 校验合法性
+		$subscribe = UserSubscribe::query()->with('user')->where('status', 1)->where('code', $code)->first();
+		if(!$subscribe){
+			exit($this->noneNode());
+		}
+
+		$user = User::query()->whereIn('status', [0, 1])->where('enable', 1)->where('id', $subscribe->user_id)->first();
+		if(!$user){
+			exit($this->noneNode());
+		}
+
+		// 更新访问次数
+		$subscribe->increment('times', 1);
+
+		// 记录每次请求
+		$this->log($subscribe->id, getClientIp(), $request->headers);
+
+		// 获取这个账号可用节点
+		$userLabelIds = UserLabel::query()->where('user_id', $user->id)->pluck('label_id');
+		if(empty($userLabelIds)){
+			exit($this->noneNode());
+		}
+
+		$query = SsNode::query()->selectRaw('ss_node.*')->leftjoin("ss_node_label", "ss_node.id", "=", "ss_node_label.node_id");
+
+		// 启用混合订阅时,加入V2Ray节点,未启用时仅下发SSR节点信息
+		if(!self::$systemConfig['mix_subscribe']){
+			$query->where('ss_node.type', 1);
+		}
+
+		$nodeList = $query->where('ss_node.status', 1)->where('ss_node.is_subscribe', 1)->whereIn('ss_node_label.label_id', $userLabelIds)->groupBy('ss_node.id')->orderBy('ss_node.sort', 'desc')->orderBy('ss_node.id', 'asc')->get()->toArray();
+		if(empty($nodeList)){
+			exit($this->noneNode());
+		}
+
+		// 打乱数组
+		if(self::$systemConfig['rand_subscribe']){
+			shuffle($nodeList);
+		}
+
+		// 控制客户端最多获取节点数
+		$scheme = '';
+
+		// 展示到期时间和剩余流量
+		if(self::$systemConfig['is_custom_subscribe']){
+			$scheme .= $this->expireDate($user);
+			$scheme .= $this->lastTraffic($user);
+		}
+
+		foreach($nodeList as $key => $node){
+			// 控制显示的节点数
+			if(self::$systemConfig['subscribe_max'] && $key >= self::$systemConfig['subscribe_max']){
+				break;
+			}
+
+			// 获取分组名称
+			if($node['type'] == 1){
+				$group = SsGroup::query()->where('id', $node['group_id'])->first();
+
+				$obfs_param = $user->obfs_param? $user->obfs_param : $node['obfs_param'];
+				$protocol_param = $node['single']? $user->port.':'.$user->passwd : $user->protocol_param;
+
+				// 生成ssr scheme
+				$ssr_str = ($node['server']? $node['server'] : $node['ip']).':'.($node['single']? $node['single_port'] : $user->port);
+				$ssr_str .= ':'.($node['single']? $node['single_protocol'] : $user->protocol).':'.($node['single']? $node['single_method'] : $user->method);
+				$ssr_str .= ':'.($node['single']? $node['single_obfs'] : $user->obfs).':'.($node['single']? base64url_encode($node['single_passwd']) : base64url_encode($user->passwd));
+				$ssr_str .= '/?obfsparam='.base64url_encode($obfs_param);
+				$ssr_str .= '&protoparam='.($node['single']? base64url_encode($user->port.':'.$user->passwd) : base64url_encode($protocol_param));
+				$ssr_str .= '&remarks='.base64url_encode($node['name']);
+				$ssr_str .= '&group='.base64url_encode(empty($group)? Helpers::systemConfig()['website_name'] : $group->name);
+				$ssr_str .= '&udpport=0';
+				$ssr_str .= '&uot=0';
+				$ssr_str = base64url_encode($ssr_str);
+				$scheme .= 'ssr://'.$ssr_str."\n";
+			}else{
+				// 生成v2ray scheme
+				$v2_json = [
+					"v"    => "2",
+					"ps"   => $node['name'],
+					"add"  => $node['server']? $node['server'] : $node['ip'],
+					"port" => $node['v2_port'],
+					"id"   => $user->vmess_id,
+					"aid"  => $node['v2_alter_id'],
+					"net"  => $node['v2_net'],
+					"type" => $node['v2_type'],
+					"host" => $node['v2_host'],
+					"path" => $node['v2_path'],
+					"tls"  => $node['v2_tls']? "tls" : ""
+				];
+
+				$scheme .= 'vmess://'.base64url_encode(json_encode($v2_json, JSON_PRETTY_PRINT))."\n";
+			}
+		}
+
+		// 适配Quantumult的自定义订阅头
+		if(self::$systemConfig['is_custom_subscribe']){
+			$headers = [
+				'Content-type'          => 'application/octet-stream; charset=utf-8',
+				'Cache-Control'         => 'no-store, no-cache, must-revalidate',
+				'Subscription-Userinfo' => 'upload='.$user->u.'; download='.$user->d.'; total='.$user->transfer_enable.'; expire='.strtotime($user->expire_time)
+			];
+
+			return Response::make(base64url_encode($scheme), 200, $headers);
+		}else{
+			return Response::make(base64url_encode($scheme));
+		}
+	}
+
+	// 写入订阅访问日志
+	private function log($subscribeId, $ip, $headers)
+	{
+		$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();
+	}
+
+	// 抛出无可用的节点信息,用于兼容防止客户端订阅失败
+	private function noneNode()
+	{
+		return base64url_encode('ssr://'.base64url_encode('0.0.0.0:1:origin:none:plain:'.base64url_encode('0000').'/?obfsparam=&protoparam=&remarks='.base64url_encode('无可用节点或账号被封禁或订阅被封禁').'&group='.base64url_encode('错误').'&udpport=0&uot=0')."\n");
+	}
+
+	/**
+	 * 过期时间
+	 *
+	 * @param object $user
+	 *
+	 * @return string
+	 */
+	private function expireDate($user)
+	{
+		$text = '到期时间:'.$user->expire_time;
+
+		return 'ssr://'.base64url_encode('0.0.0.1:1:origin:none:plain:'.base64url_encode('0000').'/?obfsparam=&protoparam=&remarks='.base64url_encode($text).'&group='.base64url_encode(Helpers::systemConfig()['website_name']).'&udpport=0&uot=0')."\n";
+	}
+
+	/**
+	 * 剩余流量
+	 *
+	 * @param object $user
+	 *
+	 * @return string
+	 */
+	private function lastTraffic($user)
+	{
+		$text = '剩余流量:'.flowAutoShow($user->transfer_enable-$user->u-$user->d);
+
+		return 'ssr://'.base64url_encode('0.0.0.2:1:origin:none:plain:'.base64url_encode('0000').'/?obfsparam=&protoparam=&remarks='.base64url_encode($text).'&group='.base64url_encode(Helpers::systemConfig()['website_name']).'&udpport=0&uot=0')."\n";
+	}
 }

+ 104 - 104
app/Http/Controllers/TicketController.php

@@ -22,109 +22,109 @@ use Response;
  */
 class TicketController extends Controller
 {
-    protected static $systemConfig;
-
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    // 工单列表
-    public function ticketList(Request $request)
-    {
-        $username = $request->input('username');
-
-        $query = Ticket::query();
-
-        if (isset($username)) {
-            $query->whereHas('user', function ($q) use ($username) {
-                $q->where('username', 'like', '%' . $username . '%');
-            });
-        }
-
-        $view['ticketList'] = $query->orderBy('id', 'desc')->paginate(10)->appends($request->except('page'));
-
-        return Response::view('ticket.ticketList', $view);
-    }
-
-    // 回复工单
-    public function replyTicket(Request $request)
-    {
-        $id = $request->input('id');
-
-        if ($request->isMethod('POST')) {
-            $content = clean($request->input('content'));
-            $content = str_replace("eval", "", str_replace("atob", "", $content));
-            $content = substr($content, 0, 300);
-
-            $obj = new TicketReply();
-            $obj->ticket_id = $id;
-            $obj->user_id = Auth::user()->id;
-            $obj->content = $content;
-            $obj->save();
-
-            if ($obj->id) {
-                // 将工单置为已回复
-                $ticket = Ticket::query()->with(['user'])->where('id', $id)->first();
-                $ticket->status = 1;
-                $ticket->save();
-
-
-                $title = "工单回复提醒";
-                $content = "标题:" . $ticket->title . "<br>管理员回复:" . $content;
-
-                // 发通知邮件
-                if (!Auth::user()->is_admin) {
-                    if (self::$systemConfig['crash_warning_email']) {
-                        $logId = Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], $title, $content);
-                        Mail::to(self::$systemConfig['crash_warning_email'])->send(new replyTicket($logId, $title, $content));
-                    }
-                } else {
-                    $logId = Helpers::addEmailLog($ticket->user->username, $title, $content);
-                    Mail::to($ticket->user->username)->send(new replyTicket($logId, $title, $content));
-                }
-
-                // 通过ServerChan发微信消息提醒管理员
-                if (!Auth::user()->is_admin) {
-                    ServerChan::send($title, $content);
-                }
-
-                return Response::json(['status' => 'success', 'data' => '', 'message' => '回复成功']);
-            } else {
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '回复失败']);
-            }
-        } else {
-            $view['ticket'] = Ticket::query()->where('id', $id)->with('user')->first();
-            $view['replyList'] = TicketReply::query()->where('ticket_id', $id)->with('user')->orderBy('id', 'asc')->get();
-
-            return Response::view('ticket.replyTicket', $view);
-        }
-    }
-
-    // 关闭工单
-    public function closeTicket(Request $request)
-    {
-        $id = $request->input('id');
-
-        $ticket = Ticket::query()->with(['user'])->where('id', $id)->first();
-        if (!$ticket) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '关闭失败']);
-        }
-
-        $ticket->status = 2;
-        $ret = $ticket->save();
-        if (!$ret) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '关闭失败']);
-        }
-
-        $title = "工单关闭提醒";
-        $content = "工单【" . $ticket->title . "】已关闭";
-
-        // 发邮件通知用户
-        $logId = Helpers::addEmailLog($ticket->user->username, $title, $content);
-        Mail::to($ticket->user->username)->send(new closeTicket($logId, $title, $content));
-
-        return Response::json(['status' => 'success', 'data' => '', 'message' => '关闭成功']);
-    }
+	protected static $systemConfig;
+
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	// 工单列表
+	public function ticketList(Request $request)
+	{
+		$username = $request->input('username');
+
+		$query = Ticket::query();
+
+		if(isset($username)){
+			$query->whereHas('user', function($q) use ($username){
+				$q->where('username', 'like', '%'.$username.'%');
+			});
+		}
+
+		$view['ticketList'] = $query->orderBy('id', 'desc')->paginate(10)->appends($request->except('page'));
+
+		return Response::view('ticket.ticketList', $view);
+	}
+
+	// 回复工单
+	public function replyTicket(Request $request)
+	{
+		$id = $request->input('id');
+
+		if($request->isMethod('POST')){
+			$content = clean($request->input('content'));
+			$content = str_replace("eval", "", str_replace("atob", "", $content));
+			$content = substr($content, 0, 300);
+
+			$obj = new TicketReply();
+			$obj->ticket_id = $id;
+			$obj->user_id = Auth::user()->id;
+			$obj->content = $content;
+			$obj->save();
+
+			if($obj->id){
+				// 将工单置为已回复
+				$ticket = Ticket::query()->with(['user'])->where('id', $id)->first();
+				$ticket->status = 1;
+				$ticket->save();
+
+
+				$title = "工单回复提醒";
+				$content = "标题:".$ticket->title."<br>管理员回复:".$content;
+
+				// 发通知邮件
+				if(!Auth::user()->is_admin){
+					if(self::$systemConfig['crash_warning_email']){
+						$logId = Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], $title, $content);
+						Mail::to(self::$systemConfig['crash_warning_email'])->send(new replyTicket($logId, $title, $content));
+					}
+				}else{
+					$logId = Helpers::addEmailLog($ticket->user->username, $title, $content);
+					Mail::to($ticket->user->username)->send(new replyTicket($logId, $title, $content));
+				}
+
+				// 通过ServerChan发微信消息提醒管理员
+				if(!Auth::user()->is_admin){
+					ServerChan::send($title, $content);
+				}
+
+				return Response::json(['status' => 'success', 'data' => '', 'message' => '回复成功']);
+			}else{
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '回复失败']);
+			}
+		}else{
+			$view['ticket'] = Ticket::query()->where('id', $id)->with('user')->first();
+			$view['replyList'] = TicketReply::query()->where('ticket_id', $id)->with('user')->orderBy('id', 'asc')->get();
+
+			return Response::view('ticket.replyTicket', $view);
+		}
+	}
+
+	// 关闭工单
+	public function closeTicket(Request $request)
+	{
+		$id = $request->input('id');
+
+		$ticket = Ticket::query()->with(['user'])->where('id', $id)->first();
+		if(!$ticket){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '关闭失败']);
+		}
+
+		$ticket->status = 2;
+		$ret = $ticket->save();
+		if(!$ret){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '关闭失败']);
+		}
+
+		$title = "工单关闭提醒";
+		$content = "工单【".$ticket->title."】已关闭";
+
+		// 发邮件通知用户
+		$logId = Helpers::addEmailLog($ticket->user->username, $title, $content);
+		Mail::to($ticket->user->username)->send(new closeTicket($logId, $title, $content));
+
+		return Response::json(['status' => 'success', 'data' => '', 'message' => '关闭成功']);
+	}
 
 }

+ 856 - 871
app/Http/Controllers/UserController.php

@@ -9,7 +9,6 @@ use App\Http\Models\Coupon;
 use App\Http\Models\Goods;
 use App\Http\Models\GoodsLabel;
 use App\Http\Models\Invite;
-use App\Http\Models\Level;
 use App\Http\Models\Order;
 use App\Http\Models\ReferralApply;
 use App\Http\Models\ReferralLog;
@@ -49,874 +48,860 @@ use Validator;
  */
 class UserController extends Controller
 {
-    protected static $systemConfig;
-
-    function __construct()
-    {
-        self::$systemConfig = Helpers::systemConfig();
-    }
-
-    public function index(Request $request)
-    {
-        $totalTransfer = Auth::user()->transfer_enable;
-        $usedTransfer = Auth::user()->u + Auth::user()->d;
-        $unusedTransfer = $totalTransfer - $usedTransfer > 0 ? $totalTransfer - $usedTransfer : 0;
-        $userRestDay = Auth::user()->traffic_reset_day;
-        $expireTime = Auth::user()->expire_time;
-        $last_day = date('t');
-        $today = date('d');
-        if ($userRestDay > $today) {
-            $resetDays = $userRestDay > $last_day ? $last_day - $today : $userRestDay - $today;
-        } else {
-            $next_last_day = date('t', strtotime('next month'));
-            $resetDays = $userRestDay > $next_last_day ? $last_day - $today + $next_last_day : $last_day - $today + $userRestDay;
-        }
-        $view['remainDays'] = date('Y-m-d') < $expireTime ? (strtotime($expireTime) - strtotime(date('Y-m-d'))) / 86400 : 0;
-        $view['resetDays'] = $resetDays;
-        $view['unusedTransfer'] = $unusedTransfer;
-        $view['expireTime'] = $expireTime;
-        $view['unusedPercent'] = $totalTransfer > 0 ? round($unusedTransfer / $totalTransfer, 2) : 0;
-        $view['noticeList'] = Article::type(2)->orderBy('id', 'desc')->Paginate(1); // 公告
-        //流量异常判断
-        $hourlyTraffic = UserTrafficHourly::query()->where('user_id', Auth::user()->id)->where('node_id', 0)->where('created_at', '>=', date('Y-m-d H:i:s', time() - 3900))->sum('total');
-        $view['isTrafficWarning'] = $hourlyTraffic < (self::$systemConfig['traffic_ban_value'] * 1073741824) ? 0 : 1;
-        //付费用户判断
-        $view['is_paying_user'] = Order::uid()->where('status', 2)->where('is_expire', 0)->where('origin_amount', '>', 0)->get()->isEmpty();
-        $view['userLoginLog'] = UserLoginLog::query()->where('user_id', Auth::user()->id)->orderBy('id', 'desc')->first(); // 近期登录日志
-
-
-        $dailyData = [];
-        $hourlyData = [];
-
-        // 节点一个月内的流量
-        // TODO:有bug
-        $userTrafficDaily = UserTrafficDaily::query()->where('user_id', Auth::user()->id)->where('node_id', 0)->where('created_at', '<=', date('Y-m-d', time()))->orderBy('created_at', 'asc')->pluck('total')->toArray();
-
-        $dailyTotal = date('d', time()) - 1; // 今天不算,减一
-        $dailyCount = count($userTrafficDaily);
-        for ($x = 0; $x < $dailyTotal - $dailyCount; $x++) {
-            $dailyData[$x] = 0;
-        }
-        for ($x = $dailyTotal - $dailyCount; $x < $dailyTotal; $x++) {
-            $dailyData[$x] = round($userTrafficDaily[$x - ($dailyTotal - $dailyCount)] / (1024 * 1024 * 1024), 3);
-        }
-
-        // 节点一天内的流量
-        $userTrafficHourly = UserTrafficHourly::query()->where('user_id', Auth::user()->id)->where('node_id', 0)->where('created_at', '>=', date('Y-m-d', time()))->orderBy('created_at', 'asc')->pluck('total')->toArray();
-        $hourlyTotal = date('H', time());
-        $hourlyCount = count($userTrafficHourly);
-        for ($x = 0; $x < $hourlyTotal - $hourlyCount; $x++) {
-            $hourlyData[$x] = 0;
-        }
-        for ($x = ($hourlyTotal - $hourlyCount); $x < $hourlyTotal; $x++) {
-            $hourlyData[$x] = round($userTrafficHourly[$x - ($hourlyTotal - $hourlyCount)] / (1024 * 1024 * 1024), 3);
-        }
-
-        // 本月天数数据
-        $monthDays = [];
-        for ($i = 1; $i <= date("d"); $i++) {
-            $monthDays[] = $i;
-        }
-        // 本日小时数据
-        $dayHours = [];
-        for ($i = 1; $i <= date("H"); $i++) {
-            $dayHours[] = $i;
-        }
-
-        $view['trafficDaily'] = "'" . implode("','", $dailyData) . "'";
-        $view['trafficHourly'] = "'" . implode("','", $hourlyData) . "'";
-        $view['monthDays'] = "'" . implode("','", $monthDays) . "'";
-        $view['dayHours'] = "'" . implode("','", $dayHours) . "'";
-
-        return Response::view('user.index', $view);
-    }
-
-    // 签到
-    public function checkIn(Request $request)
-    {
-        // 系统开启登录加积分功能才可以签到
-        if (!self::$systemConfig['is_checkin']) {
-            return Response::json(['status' => 'fail', 'message' => '系统未开启签到功能']);
-        }
-
-        // 已签到过,验证是否有效
-        if (Cache::has('userCheckIn_' . Auth::user()->id)) {
-            return Response::json(['status' => 'fail', 'message' => '已经签到过了,明天再来吧']);
-        }
-
-        $traffic = mt_rand(self::$systemConfig['min_rand_traffic'], self::$systemConfig['max_rand_traffic']);
-        $ret = User::uid()->increment('transfer_enable', $traffic * 1048576);
-        if (!$ret) {
-            return Response::json(['status' => 'fail', 'message' => '签到失败,系统异常']);
-        }
-
-        // 写入用户流量变动记录
-        Helpers::addUserTrafficModifyLog(Auth::user()->id, 0, Auth::user()->transfer_enable, Auth::user()->transfer_enable + $traffic * 1048576, '[签到]');
-
-        // 多久后可以再签到
-        $ttl = self::$systemConfig['traffic_limit_time'] ? self::$systemConfig['traffic_limit_time'] : 1440;
-        Cache::put('userCheckIn_' . Auth::user()->id, '1', $ttl);
-
-        return Response::json(['status' => 'success', 'message' => '签到成功,系统送您 ' . $traffic . 'M 流量']);
-    }
-
-    // 节点列表
-    public function nodeList(Request $request)
-    {
-    // 节点列表
-        $userLabelIds = UserLabel::uid()->pluck('label_id');
-        if (empty($userLabelIds)) {
-            $view['nodeList'] = [];
-            $view['allNodes'] = '';
-
-            return Response::view('user.nodeList', $view);
-        }
-
-        // 获取当前用户可用节点
-        $nodeList = DB::table('ss_node')
-            ->selectRaw('ss_node.*')
-            ->leftJoin('ss_node_label', 'ss_node.id', '=', 'ss_node_label.node_id')
-            ->whereIn('ss_node_label.label_id', $userLabelIds)
-            ->where('ss_node.status', 1)
-            ->groupBy('ss_node.id')
-            ->orderBy('ss_node.sort', 'desc')
-            ->orderBy('ss_node.id', 'asc')
-            ->get();
-
-        $allNodes = ''; // 全部节点SSR链接,用于一键复制所有节点
-        foreach ($nodeList as &$node) {
-            // 获取分组名称
-            $group = SsGroup::query()->where('id', $node->group_id)->first();
-
-            if ($node->type == 1) {
-                $server = $node->server ?: $node->ip;
-                $port = $node->single ? $node->port : Auth::user()->port;
-                $protocol = $node->single ? $node->protocol : Auth::user()->protocol;
-                $method = $node->single ? $node->method : Auth::user()->method;
-                $obfs = $node->single ? $node->obfs : Auth::user()->obfs;
-                $passwd = $node->single ? $node->passwd : Auth::user()->passwd;
-                $obfs_param = $node->single ? $node->obfs_param : Auth::user()->obfs_param;
-                $protocol_param = $node->single ? Auth::user()->port . ':' . Auth::user()->passwd : Auth::user()->protocol_param;
-                $group = empty($group) ? Helpers::systemConfig()['website_name'] : $group->name;
-
-                // 生成ssr scheme
-                $ssr_str = $server . ':' . $port;
-                $ssr_str .= ':' . $protocol . ':' . $method;
-                $ssr_str .= ':' . $obfs . ':' . base64url_encode($passwd);
-                $ssr_str .= '/?obfsparam=' . base64url_encode($obfs_param);
-                $ssr_str .= '&protoparam=' . base64url_encode($protocol_param);
-                $ssr_str .= '&remarks=' . base64url_encode($node->name);
-                $ssr_str .= '&group=' . base64url_encode($group);
-                $ssr_str .= '&udpport=0';
-                $ssr_str .= '&uot=0';
-                $ssr_str = base64url_encode($ssr_str);
-                $ssr_scheme = 'ssr://' . $ssr_str;
-
-                // 生成ss scheme
-                $ss_str = Auth::user()->method . ':' . Auth::user()->passwd . '@';
-                $ss_str .= ($node->server ?: $node->ip) . ':' . Auth::user()->port;
-                $ss_str = base64url_encode($ss_str) . '#' . 'VPN';
-                $ss_scheme = 'ss://' . $ss_str;
-
-                // 生成文本配置信息
-                $txt = "服务器:" . $server . PHP_EOL;
-                if ($node->ipv6) {
-                    $txt .= "IPv6:" . $node->ipv6 . PHP_EOL;
-                }
-                $txt .= "远程端口:" . $port . PHP_EOL;
-                $txt .= "密码:" . $passwd . PHP_EOL;
-                $txt .= "加密方法:" . $method . PHP_EOL;
-                $txt .= "路由:绕过局域网及中国大陆地址" . PHP_EOL . PHP_EOL;
-                $txt .= "协议:" . $protocol . PHP_EOL;
-                $txt .= "协议参数:" . $protocol_param . PHP_EOL;
-                $txt .= "混淆方式:" . $obfs . PHP_EOL;
-                $txt .= "混淆参数:" . $obfs_param . PHP_EOL;
-                $txt .= "本地端口:1080" . PHP_EOL;
-
-                $node->txt = $txt;
-                $node->ssr_scheme = $ssr_scheme;
-                $node->ss_scheme = $node->compatible ? $ss_scheme : ''; // 节点兼容原版才显示
-
-                $allNodes .= $ssr_scheme . '|';
-            } else {
-                // 生成v2ray scheme
-                $v2_json = ["v" => "2", "ps" => $node->name, "add" => $node->server ?: $node->ip, "port" => $node->v2_port, "id" => Auth::user()->vmess_id, "aid" => $node->v2_alter_id, "net" => $node->v2_net, "type" => $node->v2_type, "host" => $node->v2_host, "path" => $node->v2_path, "tls" => $node->v2_tls == 1 ? "tls" : ""];
-                $v2_scheme = 'vmess://' . base64_encode(json_encode($v2_json, JSON_PRETTY_PRINT));
-
-                // 生成文本配置信息
-                $txt = "服务器:" . $node->server ?: $node->ip . PHP_EOL;
-                if ($node->ipv6) {
-                    $txt .= "IPv6:" . $node->ipv6 . PHP_EOL;
-                }
-                $txt .= "端口:" . $node->v2_port . PHP_EOL;
-                $txt .= "加密方式:" . $node->v2_method . PHP_EOL;
-                $txt .= "用户ID:" . Auth::user()->vmess_id . PHP_EOL;
-                $txt .= "额外ID:" . $node->v2_alter_id . PHP_EOL;
-                $txt .= "传输协议:" . $node->v2_net . PHP_EOL;
-                $txt .= "伪装类型:" . $node->v2_type . PHP_EOL;
-                $txt .= $node->v2_host ? "伪装域名:" . $node->v2_host . PHP_EOL : "";
-                $txt .= $node->v2_path ? "路径:" . $node->v2_path . PHP_EOL : "";
-                $txt .= $node->v2_tls ? "TLS:tls" . PHP_EOL : "";
-
-                $node->txt = $txt;
-                $node->v2_scheme = $v2_scheme;
-            }
-
-            // 节点在线状态
-            $nodeInfo = SsNodeInfo::query()->where('node_id', $node->id)->where('log_time', '>=', strtotime("-10 minutes"))->orderBy('id', 'desc')->first();
-            $node->online_status = $nodeInfo ? 1 : 0;
-
-            // 节点标签
-            $node->labels = SsNodeLabel::query()->with('labelInfo')->where('node_id', $node->id)->first();
-        }
-
-        $view['allNodes'] = rtrim($allNodes, "|");
-        $view['nodeList'] = $nodeList;
-
-        return Response::view('user.nodeList', $view);
-    }
-
-    // 公告详情
-    public function article(Request $request)
-    {
-        $view['info'] = Article::query()->findOrFail($request->id);
-
-        return Response::view('user.article', $view);
-    }
-
-    // 修改个人资料
-    public function profile(Request $request)
-    {
-        if ($request->isMethod('POST')) {
-            $old_password = trim($request->input('old_password'));
-            $new_password = trim($request->input('new_password'));
-            $wechat = $request->input('wechat');
-            $qq = $request->input('qq');
-            $passwd = trim($request->input('passwd'));
-
-            // 修改密码
-            if ($old_password && $new_password) {
-                if (!Hash::check($old_password, Auth::user()->password)) {
-                    return Redirect::to('profile#tab_1')->withErrors('旧密码错误,请重新输入');
-                } elseif (Hash::check($new_password, Auth::user()->password)) {
-                    return Redirect::to('profile#tab_1')->withErrors('新密码不可与旧密码一样,请重新输入');
-                }
-
-                // 演示环境禁止改管理员密码
-                if (env('APP_DEMO') && Auth::user()->id == 1) {
-                    return Redirect::to('profile#tab_1')->withErrors('演示环境禁止修改管理员密码');
-                }
-
-                $ret = User::uid()->update(['password' => Hash::make($new_password)]);
-                if (!$ret) {
-                    return Redirect::to('profile#tab_1')->withErrors('修改失败');
-                } else {
-                    return Redirect::to('profile#tab_1')->with('successMsg', '修改成功');
-                }
-            }
-
-            // 修改联系方式
-            if ($wechat || $qq) {
-                if (empty(clean($wechat)) && empty(clean($qq))) {
-                    return Redirect::to('profile#tab_2')->withErrors('修改失败');
-                }
-
-                $ret = User::uid()->update(['wechat' => $wechat, 'qq' => $qq]);
-                if (!$ret) {
-                    return Redirect::to('profile#tab_2')->withErrors('修改失败');
-                } else {
-                    return Redirect::to('profile#tab_2')->with('successMsg', '修改成功');
-                }
-            }
-
-            // 修改代理密码
-            if ($passwd) {
-                $ret = User::uid()->update(['passwd' => $passwd]);
-                if (!$ret) {
-                    return Redirect::to('profile#tab_3')->withErrors('修改失败');
-                } else {
-                    return Redirect::to('profile#tab_3')->with('successMsg', '修改成功');
-                }
-            }
-
-            return Redirect::to('profile#tab_1')->withErrors('非法请求');
-        } else {
-            return Response::view('user.profile');
-        }
-    }
-
-    // 商品列表
-    public function services(Request $request)
-    {
-        // 余额充值商品,只取10个
-        $view['chargeGoodsList'] = Goods::type(3)->where('status', 1)->orderBy('price', 'asc')->orderBy('price', 'asc')->limit(10)->get();
-        $view['goodsList'] = Goods::query()->where('status', 1)->where('type', '<=', '2')->orderBy('type', 'desc')->orderBy('sort', 'desc')->paginate(10)->appends($request->except('page'));
-
-        return Response::view('user.services', $view);
-    }
-
-    // 工单
-    public function ticketList(Request $request)
-    {
-        $view['ticketList'] = Ticket::uid()->orderBy('id', 'desc')->paginate(10)->appends($request->except('page'));
-
-        return Response::view('user.ticketList', $view);
-    }
-
-    // 订单
-    public function invoices(Request $request)
-    {
-        $view['orderList'] = Order::uid()->with(['user', 'goods', 'coupon', 'payment'])->orderBy('oid', 'desc')->paginate(10)->appends($request->except('page'));
-
-        return Response::view('user.invoices', $view);
-    }
-
-    // 订单明细
-    public function invoiceDetail(Request $request, $sn)
-    {
-        $view['order'] = Order::uid()->with(['goods', 'coupon', 'payment'])->where('order_sn', $sn)->firstOrFail();
-
-        return Response::view('user.invoiceDetail', $view);
-    }
-
-    // 添加工单
-    public function addTicket(Request $request)
-    {
-        $title = $request->input('title');
-        $content = clean($request->input('content'));
-        $content = str_replace("eval", "", str_replace("atob", "", $content));
-
-        if (empty($title) || empty($content)) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '请输入标题和内容']);
-        }
-
-        $obj = new Ticket();
-        $obj->user_id = Auth::user()->id;
-        $obj->title = $title;
-        $obj->content = $content;
-        $obj->status = 0;
-        $obj->save();
-
-        if ($obj->id) {
-            $emailTitle = "新工单提醒";
-            $content = "标题:【" . $title . "】<br>用户:" . Auth::user()->username . "<br>内容:" . $content;
-
-            // 发邮件通知管理员
-            if (self::$systemConfig['crash_warning_email']) {
-                $logId = Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], $emailTitle, $content);
-                Mail::to(self::$systemConfig['crash_warning_email'])->send(new newTicket($logId, $emailTitle, $content));
-            }
-
-            ServerChan::send($emailTitle, $content);
-
-            return Response::json(['status' => 'success', 'data' => '', 'message' => '提交成功']);
-        } else {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '提交失败']);
-        }
-    }
-
-    // 回复工单
-    public function replyTicket(Request $request)
-    {
-        $id = $request->input('id');
-
-        $ticket = Ticket::uid()->with('user')->where('id', $id)->firstOrFail();
-
-        if ($request->isMethod('POST')) {
-            $content = clean($request->input('content'));
-            $content = str_replace("eval", "", str_replace("atob", "", $content));
-            $content = substr($content, 0, 300);
-
-            if (empty($content)) {
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '回复内容不能为空']);
-            }
-
-            if ($ticket->status == 2) {
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '错误:该工单已关闭']);
-            }
-
-            $obj = new TicketReply();
-            $obj->ticket_id = $id;
-            $obj->user_id = Auth::user()->id;
-            $obj->content = $content;
-            $obj->save();
-
-            if ($obj->id) {
-                // 重新打开工单
-                $ticket->status = 0;
-                $ticket->save();
-
-                $title = "工单回复提醒";
-                $content = "标题:【" . $ticket->title . "】<br>用户回复:" . $content;
-
-                // 发邮件通知管理员
-                if (self::$systemConfig['crash_warning_email']) {
-                    $logId = Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], $title, $content);
-                    Mail::to(self::$systemConfig['crash_warning_email'])->send(new replyTicket($logId, $title, $content));
-                }
-
-                ServerChan::send($title, $content);
-
-                return Response::json(['status' => 'success', 'data' => '', 'message' => '回复成功']);
-            } else {
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '回复失败']);
-            }
-        } else {
-            $view['ticket'] = $ticket;
-            $view['replyList'] = TicketReply::query()->where('ticket_id', $id)->with('user')->orderBy('id', 'asc')->get();
-
-            return Response::view('user.replyTicket', $view);
-        }
-    }
-
-    // 关闭工单
-    public function closeTicket(Request $request)
-    {
-        $id = $request->input('id');
-
-        $ret = Ticket::uid()->where('id', $id)->update(['status' => 2]);
-        if ($ret) {
-            ServerChan::send('工单关闭提醒', '工单:ID' . $id . '用户已手动关闭');
-
-            return Response::json(['status' => 'success', 'data' => '', 'message' => '关闭成功']);
-        } else {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '关闭失败']);
-        }
-    }
-
-    // 邀请码
-    public function invite(Request $request)
-    {
-        if (Order::uid()->where('status', 2)->where('is_expire', 0)->where('origin_amount', '>', 0)->get()->isEmpty()) {
-            return Response::view('auth.error', ['message' => '本功能对非付费用户禁用!请 <a class="btn btn-sm btn-danger" href="/">返回</a>']);
-        }
-        // 已生成的邀请码数量
-        $num = Invite::uid()->count();
-
-        $view['num'] = self::$systemConfig['invite_num'] - $num <= 0 ? 0 : self::$systemConfig['invite_num'] - $num; // 还可以生成的邀请码数量
-        $view['inviteList'] = Invite::uid()->with(['generator', 'user'])->paginate(10); // 邀请码列表
-        $view['referral_traffic'] = flowAutoShow(self::$systemConfig['referral_traffic'] * 1048576);
-        $view['referral_percent'] = self::$systemConfig['referral_percent'];
-
-        return Response::view('user.invite', $view);
-    }
-
-    // 生成邀请码
-    public function makeInvite(Request $request)
-    {
-        // 已生成的邀请码数量
-        $num = Invite::uid()->count();
-        if ($num >= self::$systemConfig['invite_num']) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '生成失败:最多只能生成' . self::$systemConfig['invite_num'] . '个邀请码']);
-        }
-
-        $obj = new Invite();
-        $obj->uid = Auth::user()->id;
-        $obj->fuid = 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::$systemConfig['user_invite_days'] . " days"));
-        $obj->save();
-
-        return Response::json(['status' => 'success', 'data' => '', 'message' => '生成成功']);
-    }
-
-    // 使用优惠券
-    public function redeemCoupon(Request $request)
-    {
-        $coupon_sn = $request->input('coupon_sn');
-
-        if (empty($coupon_sn)) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '优惠券不能为空']);
-        }
-
-        $coupon = Coupon::query()->where('sn', $coupon_sn)->whereIn('type', [1, 2])->first();
-        if (!$coupon) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '该优惠券不存在']);
-        } elseif ($coupon->status == 1) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '该优惠券已使用,请换一个试试']);
-        } elseif ($coupon->status == 2) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '该优惠券已失效,请换一个试试']);
-        } elseif ($coupon->available_end < time()) {
-            $coupon->status = 2;
-            $coupon->save();
-
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '该优惠券已失效,请换一个试试']);
-        } elseif ($coupon->available_start > time()) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '该优惠券尚不可用,请换一个试试']);
-        }
-
-        $data = ['name' => $coupon->name ,'type' => $coupon->type, 'amount' => $coupon->amount, 'discount' => $coupon->discount];
-
-        return Response::json(['status' => 'success', 'data' => $data, 'message' => '优惠券有效']);
-    }
-
-    // 购买服务
-    public function buy(Request $request, $goods_id)
-    {
-        $coupon_sn = $request->input('coupon_sn');
-        // 余额支付
-        if ($request->isMethod('POST')) {
-            $goods = Goods::query()->with(['label'])->where('status', 1)->where('id', $goods_id)->first();
-            if (!$goods) {
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:商品或服务已下架']);
-            }
-
-            // 限购控制:all-所有商品限购, free-价格为0的商品限购, none-不限购(默认)
-            $strategy = self::$systemConfig['goods_purchase_limit_strategy'];
-            if ($strategy == 'all' || ($strategy == 'package' && $goods->type == 2) || ($strategy == 'free' && $goods->price == 0) || ($strategy == 'package&free' && ($goods->type == 2 || $goods->price == 0))) {
-                $noneExpireGoodExist = Order::uid()->where('status', '>=', 0)->where('is_expire', 0)->where('goods_id', $goods_id)->exists();
-                if ($noneExpireGoodExist) {
-                    return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:商品不可重复购买']);
-                }
-            }
-
-            // 单个商品限购
-            if ($goods->is_limit == 1) {
-                $noneExpireOrderExist = Order::uid()->where('status', '>=', 0)->where('goods_id', $goods_id)->exists();
-                if ($noneExpireOrderExist) {
-                    return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:此商品每人限购1次']);
-                }
-            }
-
-            // 使用优惠券
-            if (!empty($coupon_sn)) {
-                $coupon = Coupon::query()->where('status', 0)->whereIn('type', [1, 2])->where('sn', $coupon_sn)->first();
-                if (!$coupon) {
-                    return Response::json(['status' => 'fail', 'data' => '', 'message' => '优惠券不存在']);
-                }
-
-                // 计算实际应支付总价
-                $amount = $coupon->type == 2 ? $goods->price * $coupon->discount / 10 : $goods->price - $coupon->amount;
-                $amount = $amount > 0 ? $amount : 0;
-            } else {
-                $amount = $goods->price;
-            }
-
-            // 价格异常判断
-            if ($amount < 0) {
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:订单总价异常']);
-            }
-
-            // 验证账号余额是否充足
-            if (Auth::user()->balance < $amount) {
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:您的余额不足,请先充值']);
-            }
-
-            // 验证账号是否存在有效期更长的套餐
-            if ($goods->type == 2) {
-                $existOrderList = Order::uid()->with('goods')->whereHas('goods', function ($q) {
-                    $q->where('type', 2);
-                })->where('is_expire', 0)->where('status', 2)->get();
-
-                foreach ($existOrderList as $vo) {
-                    if ($vo->goods->days > $goods->days) {
-                        return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:您已存在有效期更长的套餐,只能购买流量包']);
-                    }
-                }
-            }
-
-            DB::beginTransaction();
-            try {
-                // 生成订单
-                $order = new Order();
-                $order->order_sn = date('ymdHis') . mt_rand(100000, 999999);
-                $order->user_id = Auth::user()->id;
-                $order->goods_id = $goods_id;
-                $order->coupon_id = !empty($coupon) ? $coupon->id : 0;
-                $order->origin_amount = $goods->price;
-                $order->amount = $amount;
-                $order->expire_at = date("Y-m-d H:i:s", strtotime("+" . $goods->days . " days"));
-                $order->is_expire = 0;
-                $order->pay_way = 1;
-                $order->status = 2;
-                $order->save();
-
-                // 扣余额
-                User::query()->where('id', Auth::user()->id)->decrement('balance', $amount * 100);
-
-                // 记录余额操作日志
-                $this->addUserBalanceLog(Auth::user()->id, $order->oid, Auth::user()->balance, Auth::user()->balance - $amount, -1 * $amount, '购买商品:' . $goods->name);
-
-                // 优惠券置为已使用
-                if (!empty($coupon)) {
-                    if ($coupon->usage == 1) {
-                        $coupon->status = 1;
-                        $coupon->save();
-                    }
-
-                    // 写入日志
-                    Helpers::addCouponLog($coupon->id, $goods_id, $order->oid, '余额支付订单使用');
-                }
-
-                // 如果买的是套餐,则先将之前购买的所有套餐置都无效,并扣掉之前所有套餐的流量,重置用户已用流量为0
-                if ($goods->type == 2) {
-                    $existOrderList = Order::query()
-                        ->with('goods')
-                        ->whereHas('goods', function ($q) {
-                            $q->where('type', 2);
-                        })
-                        ->where('user_id', Auth::user()->id)
-                        ->where('oid', '<>', $order->oid)
-                        ->where('is_expire', 0)
-                        ->where('status', 2)
-                        ->get();
-
-                    foreach ($existOrderList as $vo) {
-                        Order::query()->where('oid', $vo->oid)->update(['is_expire' => 1]);
-
-                        // 先判断,防止手动扣减过流量的用户流量被扣成负数
-                        if ($order->user->transfer_enable - $vo->goods->traffic * 1048576 <= 0) {
-                            // 写入用户流量变动记录
-                            Helpers::addUserTrafficModifyLog(Auth::user()->id, $order->oid, 0, 0, '[余额支付]用户购买套餐,先扣减之前套餐的流量(扣完)');
-
-                            User::query()->where('id', Auth::user()->id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
-                        } else {
-                            // 写入用户流量变动记录
-                            $user = User::query()->uid()->first(); // 重新取出user信息
-                            Helpers::addUserTrafficModifyLog(Auth::user()->id, $order->oid, $user->transfer_enable, ($user->transfer_enable - $vo->goods->traffic * 1048576), '[余额支付]用户购买套餐,先扣减之前套餐的流量(未扣完)');
-
-                            User::query()->uid()->update(['u' => 0, 'd' => 0]);
-                            User::query()->uid()->decrement('transfer_enable', $vo->goods->traffic * 1048576);
-                        }
-                    }
-                }
-
-                // 写入用户流量变动记录
-                $user = User::query()->uid()->first(); // 重新取出user信息
-                Helpers::addUserTrafficModifyLog($user->id, $order->oid, $user->transfer_enable, ($user->transfer_enable + $goods->traffic * 1048576), '[余额支付]用户购买商品,加上流量');
-
-                // 把商品的流量加到账号上
-                User::query()->where('id', $user->id)->increment('transfer_enable', $goods->traffic * 1048576);
-
-                // 计算账号过期时间
-                if ($user->expire_time < date('Y-m-d', strtotime("+" . $goods->days . " days"))) {
-                    $expireTime = date('Y-m-d', strtotime("+" . $goods->days . " days"));
-                } else {
-                    $expireTime = $user->expire_time;
-                }
-
-                // 套餐就改流量重置日,流量包不改
-                if ($goods->type == 2) {
-                    $traffic_reset_day = date('d');
-                    User::query()->uid()->update(['traffic_reset_day' => $traffic_reset_day, 'expire_time' => $expireTime, 'enable' => 1]);
-                } else {
-                    User::query()->uid()->update(['expire_time' => $expireTime, 'enable' => 1]);
-                }
-
-                // 写入用户标签
-                if ($goods->label) {
-                    // 用户默认标签
-                    $defaultLabels = [];
-                    if (self::$systemConfig['initial_labels_for_user']) {
-                        $defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
-                    }
-
-                    // 取出现有的标签
-                    $userLabels = UserLabel::query()->where('user_id', Auth::user()->id)->pluck('label_id')->toArray();
-                    $goodsLabels = GoodsLabel::query()->where('goods_id', $goods_id)->pluck('label_id')->toArray();
-
-                    // 标签去重
-                    $newUserLabels = array_values(array_unique(array_merge($userLabels, $goodsLabels, $defaultLabels)));
-
-                    // 删除用户所有标签
-                    UserLabel::query()->where('user_id', Auth::user()->id)->delete();
-
-                    // 生成标签
-                    foreach ($newUserLabels as $vo) {
-                        $obj = new UserLabel();
-                        $obj->user_id = Auth::user()->id;
-                        $obj->label_id = $vo;
-                        $obj->save();
-                    }
-                }
-
-                // 写入返利日志
-                if ($user->referral_uid) {
- $this->addReferralLog($user->id, $user->referral_uid, $order->oid, $amount, $amount * self::$systemConfig['referral_percent']);
-                }
-
-                // 取消重复返利
-                User::query()->where('id', $order->user_id)->update(['referral_uid' => 0]);
-
-                DB::commit();
-
-                return Response::json(['status' => 'success', 'data' => '', 'message' => '支付成功']);
-            } catch (Exception $e) {
-                Log::error('支付订单失败:' . $e);
-
-                DB::rollBack();
-
-                return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:' . $e->getMessage()]);
-            }
-        } else {
-            $goods = Goods::query()->where('id', $goods_id)->where('status', 1)->first();
-            if (empty($goods)) {
-                return Redirect::to('services');
-            }
-
-            $view['goods'] = $goods;
-
-            return Response::view('user.buy', $view);
-        }
-    }
-
-    // 推广返利
-    public function referral(Request $request)
-    {
-        if (Order::uid()->where('status', 2)->where('is_expire', 0)->where('origin_amount', '>', 0)->get()->isEmpty()) {
-            return Response::view('auth.error', ['message' => '本功能对非付费用户禁用!请 <a class="btn btn-sm btn-danger" href="/">返回</a>']);
-        }
-        $view['referral_traffic'] = flowAutoShow(self::$systemConfig['referral_traffic'] * 1048576);
-        $view['referral_percent'] = self::$systemConfig['referral_percent'];
-        $view['referral_money'] = self::$systemConfig['referral_money'];
-        $view['totalAmount'] = ReferralLog::uid()->sum('ref_amount') / 100;
-        $view['canAmount'] = ReferralLog::uid()->where('status', 0)->sum('ref_amount') / 100;
-        $view['link'] = self::$systemConfig['website_url'] . '/register?aff=' . Auth::user()->id;
-        $view['referralLogList'] = ReferralLog::uid()->with('user')->orderBy('id', 'desc')->paginate(10, ['*'], 'log_page');
-        $view['referralApplyList'] = ReferralApply::uid()->with('user')->orderBy('id', 'desc')->paginate(10, ['*'], 'apply_page');
-        $view['referralUserList'] = User::query()->select(['username', 'created_at'])->where('referral_uid', Auth::user()->id)->orderBy('id', 'desc')->paginate(10, ['*'], 'user_page');
-
-        return Response::view('user.referral', $view);
-    }
-
-    // 申请提现
-    public function extractMoney(Request $request)
-    {
-        // 判断账户是否过期
-        if (Auth::user()->expire_time < date('Y-m-d')) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '申请失败:账号已过期,请先购买服务吧']);
-        }
-
-        // 判断是否已存在申请
-        $referralApply = ReferralApply::uid()->whereIn('status', [0, 1])->first();
-        if ($referralApply) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '申请失败:已存在申请,请等待之前的申请处理完']);
-        }
-
-        // 校验可以提现金额是否超过系统设置的阀值
-        $ref_amount = ReferralLog::uid()->where('status', 0)->sum('ref_amount');
-        $ref_amount = $ref_amount / 100;
-        if ($ref_amount < self::$systemConfig['referral_money']) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '申请失败:满' . self::$systemConfig['referral_money'] . '元才可以提现,继续努力吧']);
-        }
-
-        // 取出本次申请关联返利日志ID
-        $link_logs = '';
-        $referralLog = ReferralLog::uid()->where('status', 0)->get();
-        foreach ($referralLog as $log) {
-            $link_logs .= $log->id . ',';
-        }
-        $link_logs = rtrim($link_logs, ',');
-
-        $obj = new ReferralApply();
-        $obj->user_id = Auth::user()->id;
-        $obj->before = $ref_amount;
-        $obj->after = 0;
-        $obj->amount = $ref_amount;
-        $obj->link_logs = $link_logs;
-        $obj->status = 0;
-        $obj->save();
-
-        return Response::json(['status' => 'success', 'data' => '', 'message' => '申请成功,请等待管理员审核']);
-    }
-
-    // 帮助中心
-    public function help(Request $request)
-    {
-        $view['articleList'] = Article::type(1)->orderBy('sort', 'desc')->orderBy('id', 'desc')->limit(10)->paginate(5);
-
-        //付费用户判断
-        $view['is_paying_user'] = Order::uid()->where('status', 2)->where('is_expire', 0)->where('origin_amount', '>', 0)->get()->isEmpty();
-        //客户端安装
-        $view['Shadowrocket_install'] = 'itms-services://?action=download-manifest&url=' . self::$systemConfig['website_url'] . '/clients/ipa.plist';
-        $view['Quantumult_install'] = 'itms-services://?action=download-manifest&url=' . self::$systemConfig['website_url'] . '/ipa.plist';
-        // 订阅连接
-        $subscribe = UserSubscribe::query()->where('user_id', Auth::user()->id)->first();
-        $view['subscribe_status'] = $subscribe->status;
-        $subscribe_link = (self::$systemConfig['subscribe_domain'] ? self::$systemConfig['subscribe_domain'] : self::$systemConfig['website_url']) . '/s/' . $subscribe->code;
-        $view['link'] = $subscribe_link;
-        $view['Shadowrocket_link'] = 'shadowrocket://add/sub://' . base64url_encode($subscribe_link) . '?remarks=' . self::$systemConfig['website_name'] . '-' . self::$systemConfig['website_url'];
-        $view['Shadowrocket_linkQrcode'] = 'sub://' . base64url_encode($subscribe_link) . '#' . base64url_encode(self::$systemConfig['website_name']);
-        $view['Quantumult_linkOut'] = 'quantumult://configuration?server=' . base64url_encode($subscribe_link) . '&filter=' . base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/Pro.conf') . '&rejection=' . base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/Rejection.conf');
-        $view['Quantumult_linkIn'] = 'quantumult://configuration?server=' . base64url_encode($subscribe_link) . '&filter=' . base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/BacktoCN.conf') . '&rejection=' . base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/Rejection.conf');
-
-        return Response::view('user.help', $view);
-    }
-
-    // 更换订阅地址
-    public function exchangeSubscribe(Request $request)
-    {
-        DB::beginTransaction();
-        try {
-            // 更换订阅码
-            UserSubscribe::uid()->update(['code' => Helpers::makeSubscribeCode()]);
-
-            // 更换连接密码
-            User::uid()->update(['passwd' => makeRandStr()]);
-
-            DB::commit();
-
-            return Response::json(['status' => 'success', 'data' => '', 'message' => '更换成功']);
-        } catch (\Exception $e) {
-            DB::rollBack();
-
-            Log::info("更换订阅地址异常:" . $e->getMessage());
-
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '更换失败' . $e->getMessage()]);
-        }
-    }
-
-    // 转换成管理员的身份
-    public function switchToAdmin(Request $request)
-    {
-        if (!Session::has('admin')) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '非法请求']);
-        }
-
-        // 管理员信息重新写入user
-        Auth::loginUsingId(Session::get('admin'));
-        Session::forget('admin');
-
-        return Response::json(['status' => 'success', 'data' => '', 'message' => "身份切换成功"]);
-    }
-
-    // 卡券余额充值
-    public function charge(Request $request)
-    {
-        $validator = Validator::make($request->all(), ['coupon_sn' => ['required', Rule::exists('coupon', 'sn')->where(function ($query) {
-            $query->where('type', 3)->where('status', 0);
-        }),]], ['coupon_sn.required' => '券码不能为空', 'coupon_sn.exists' => '该券不可用']);
-
-        if ($validator->fails()) {
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => $validator->getMessageBag()->first()]);
-        }
-
-        $coupon = Coupon::query()->where('sn', $request->input('coupon_sn'))->first();
-
-        DB::beginTransaction();
-        try {
-            // 写入日志
-            $this->addUserBalanceLog(Auth::user()->id, 0, Auth::user()->balance, Auth::user()->balance + $coupon->amount, $coupon->amount, '用户手动充值 - [充值券:' . $request->input('coupon_sn') . ']');
-
-            // 余额充值
-            User::uid()->increment('balance', $coupon->amount * 100);
-
-            // 更改卡券状态
-            $coupon->status = 1;
-            $coupon->save();
-
-            // 写入卡券日志
-            Helpers::addCouponLog($coupon->id, 0, 0, '账户余额充值使用');
-
-            DB::commit();
-
-            return Response::json(['status' => 'success', 'data' => '', 'message' => '充值成功']);
-        } catch (\Exception $e) {
-            Log::error($e);
-            DB::rollBack();
-
-            return Response::json(['status' => 'fail', 'data' => '', 'message' => '充值失败']);
-        }
-    }
+	protected static $systemConfig;
+
+	function __construct()
+	{
+		self::$systemConfig = Helpers::systemConfig();
+	}
+
+	public function index(Request $request)
+	{
+		$totalTransfer = Auth::user()->transfer_enable;
+		$usedTransfer = Auth::user()->u+Auth::user()->d;
+		$unusedTransfer = $totalTransfer-$usedTransfer > 0? $totalTransfer-$usedTransfer : 0;
+		$userRestDay = Auth::user()->traffic_reset_day;
+		$expireTime = Auth::user()->expire_time;
+		$last_day = date('t');
+		$today = date('d');
+		if($userRestDay > $today){
+			$resetDays = $userRestDay > $last_day? $last_day-$today : $userRestDay-$today;
+		}else{
+			$next_last_day = date('t', strtotime('next month'));
+			$resetDays = $userRestDay > $next_last_day? $last_day-$today+$next_last_day : $last_day-$today+$userRestDay;
+		}
+		$view['remainDays'] = date('Y-m-d') < $expireTime? (strtotime($expireTime)-strtotime(date('Y-m-d')))/86400 : 0;
+		$view['resetDays'] = $resetDays;
+		$view['unusedTransfer'] = $unusedTransfer;
+		$view['expireTime'] = $expireTime;
+		$view['banedTime'] =  Auth::user()->ban_time != 0? date('Y-m-d H:i:s', Auth::user()->ban_time) : 0;;
+		$view['unusedPercent'] = $totalTransfer > 0? round($unusedTransfer/$totalTransfer, 2) : 0;
+		$view['noticeList'] = Article::type(2)->orderBy('id', 'desc')->Paginate(1); // 公告
+		//流量异常判断
+		$hourlyTraffic = UserTrafficHourly::query()->where('user_id', Auth::user()->id)->where('node_id', 0)->where('created_at', '>=', date('Y-m-d H:i:s', time()-3900))->sum('total');
+		$view['isTrafficWarning'] = $hourlyTraffic < (self::$systemConfig['traffic_ban_value']*1073741824)? 0 : 1;
+		//付费用户判断
+		$view['not_paying_user'] = Order::uid()->where('status', 2)->where('is_expire', 0)->where('origin_amount', '>', 0)->get()->isEmpty();
+		$view['userLoginLog'] = UserLoginLog::query()->where('user_id', Auth::user()->id)->orderBy('id', 'desc')->first(); // 近期登录日志
+
+
+		$dailyData = [];
+		$hourlyData = [];
+
+		// 节点一个月内的流量
+		// TODO:有bug
+		$userTrafficDaily = UserTrafficDaily::query()->where('user_id', Auth::user()->id)->where('node_id', 0)->where('created_at', '<=', date('Y-m-d', time()))->orderBy('created_at', 'asc')->pluck('total')->toArray();
+
+		$dailyTotal = date('d', time())-1; // 今天不算,减一
+		$dailyCount = count($userTrafficDaily);
+		for($x = 0; $x < $dailyTotal-$dailyCount; $x++){
+			$dailyData[$x] = 0;
+		}
+		for($x = $dailyTotal-$dailyCount; $x < $dailyTotal; $x++){
+			$dailyData[$x] = round($userTrafficDaily[$x-($dailyTotal-$dailyCount)]/(1024*1024*1024), 3);
+		}
+
+		// 节点一天内的流量
+		$userTrafficHourly = UserTrafficHourly::query()->where('user_id', Auth::user()->id)->where('node_id', 0)->where('created_at', '>=', date('Y-m-d', time()))->orderBy('created_at', 'asc')->pluck('total')->toArray();
+		$hourlyTotal = date('H', time());
+		$hourlyCount = count($userTrafficHourly);
+		for($x = 0; $x < $hourlyTotal-$hourlyCount; $x++){
+			$hourlyData[$x] = 0;
+		}
+		for($x = ($hourlyTotal-$hourlyCount); $x < $hourlyTotal; $x++){
+			$hourlyData[$x] = round($userTrafficHourly[$x-($hourlyTotal-$hourlyCount)]/(1024*1024*1024), 3);
+		}
+
+		// 本月天数数据
+		$monthDays = [];
+		for($i = 1; $i <= date("d"); $i++){
+			$monthDays[] = $i;
+		}
+		// 本日小时数据
+		$dayHours = [];
+		for($i = 1; $i <= date("H"); $i++){
+			$dayHours[] = $i;
+		}
+
+		$view['trafficDaily'] = "'".implode("','", $dailyData)."'";
+		$view['trafficHourly'] = "'".implode("','", $hourlyData)."'";
+		$view['monthDays'] = "'".implode("','", $monthDays)."'";
+		$view['dayHours'] = "'".implode("','", $dayHours)."'";
+
+		return Response::view('user.index', $view);
+	}
+
+	// 签到
+	public function checkIn(Request $request)
+	{
+		// 系统开启登录加积分功能才可以签到
+		if(!self::$systemConfig['is_checkin']){
+			return Response::json(['status' => 'fail', 'message' => '系统未开启签到功能']);
+		}
+
+		// 已签到过,验证是否有效
+		if(Cache::has('userCheckIn_'.Auth::user()->id)){
+			return Response::json(['status' => 'fail', 'message' => '已经签到过了,明天再来吧']);
+		}
+
+		$traffic = mt_rand(self::$systemConfig['min_rand_traffic'], self::$systemConfig['max_rand_traffic']);
+		$ret = User::uid()->increment('transfer_enable', $traffic*1048576);
+		if(!$ret){
+			return Response::json(['status' => 'fail', 'message' => '签到失败,系统异常']);
+		}
+
+		// 写入用户流量变动记录
+		Helpers::addUserTrafficModifyLog(Auth::user()->id, 0, Auth::user()->transfer_enable, Auth::user()->transfer_enable+$traffic*1048576, '[签到]');
+
+		// 多久后可以再签到
+		$ttl = self::$systemConfig['traffic_limit_time']? self::$systemConfig['traffic_limit_time'] : 1440;
+		Cache::put('userCheckIn_'.Auth::user()->id, '1', $ttl);
+
+		return Response::json(['status' => 'success', 'message' => '签到成功,系统送您 '.$traffic.'M 流量']);
+	}
+
+	// 节点列表
+	public function nodeList(Request $request)
+	{
+		// 节点列表
+		$userLabelIds = UserLabel::uid()->pluck('label_id');
+		if(empty($userLabelIds)){
+			$view['nodeList'] = [];
+			$view['allNodes'] = '';
+
+			return Response::view('user.nodeList', $view);
+		}
+
+		// 获取当前用户可用节点
+		$nodeList = DB::table('ss_node')->selectRaw('ss_node.*')->leftJoin('ss_node_label', 'ss_node.id', '=', 'ss_node_label.node_id')->whereIn('ss_node_label.label_id', $userLabelIds)->where('ss_node.status', 1)->groupBy('ss_node.id')->orderBy('ss_node.sort', 'desc')->orderBy('ss_node.id', 'asc')->get();
+
+		$allNodes = ''; // 全部节点SSR链接,用于一键复制所有节点
+		foreach($nodeList as &$node){
+			// 获取分组名称
+			$group = SsGroup::query()->where('id', $node->group_id)->first();
+
+			if($node->type == 1){
+				$server = $node->server? : $node->ip;
+				$port = $node->single? $node->single_port : Auth::user()->port;
+				$protocol = $node->single? $node->single_protocol : Auth::user()->protocol;
+				$method = $node->single? $node->single_method : Auth::user()->method;
+				$obfs = $node->single? $node->single_obfs : Auth::user()->obfs;
+				$passwd = $node->single? $node->single_passwd : Auth::user()->passwd;
+				$obfs_param = Auth::user()->obfs_param? Auth::user()->obfs_param : $node->obfs_param;
+				$protocol_param = $node->single? Auth::user()->port.':'.Auth::user()->passwd : Auth::user()->protocol_param;
+				$group = empty($group)? Helpers::systemConfig()['website_name'] : $group->name;
+
+				// 生成ssr scheme
+				$ssr_str = $server.':'.$port;
+				$ssr_str .= ':'.$protocol.':'.$method;
+				$ssr_str .= ':'.$obfs.':'.base64url_encode($passwd);
+				$ssr_str .= '/?obfsparam='.base64url_encode($obfs_param);
+				$ssr_str .= '&protoparam='.base64url_encode($protocol_param);
+				$ssr_str .= '&remarks='.base64url_encode($node->name);
+				$ssr_str .= '&group='.base64url_encode($group);
+				$ssr_str .= '&udpport=0';
+				$ssr_str .= '&uot=0';
+				$ssr_str = base64url_encode($ssr_str);
+				$ssr_scheme = 'ssr://'.$ssr_str;
+
+				// 生成ss scheme
+				$ss_str = Auth::user()->method.':'.Auth::user()->passwd.'@';
+				$ss_str .= ($node->server? : $node->ip).':'.Auth::user()->port;
+				$ss_str = base64url_encode($ss_str).'#'.'VPN';
+				$ss_scheme = 'ss://'.$ss_str;
+
+				// 生成文本配置信息
+				$txt = "服务器:".$server.PHP_EOL;
+				if($node->ipv6){
+					$txt .= "IPv6:".$node->ipv6.PHP_EOL;
+				}
+				$txt .= "远程端口:".$port.PHP_EOL;
+				$txt .= "密码:".$passwd.PHP_EOL;
+				$txt .= "加密方法:".$method.PHP_EOL;
+				$txt .= "路由:绕过局域网及中国大陆地址".PHP_EOL.PHP_EOL;
+				$txt .= "协议:".$protocol.PHP_EOL;
+				$txt .= "协议参数:".$protocol_param.PHP_EOL;
+				$txt .= "混淆方式:".$obfs.PHP_EOL;
+				$txt .= "混淆参数:".$obfs_param.PHP_EOL;
+				$txt .= "本地端口:1080".PHP_EOL;
+
+				$node->txt = $txt;
+				$node->ssr_scheme = $ssr_scheme;
+				$node->ss_scheme = $node->compatible? $ss_scheme : ''; // 节点兼容原版才显示
+
+				$allNodes .= $ssr_scheme.'|';
+			}else{
+				// 生成v2ray scheme
+				$v2_json = ["v" => "2", "ps" => $node->name, "add" => $node->server? : $node->ip, "port" => $node->v2_port, "id" => Auth::user()->vmess_id, "aid" => $node->v2_alter_id, "net" => $node->v2_net, "type" => $node->v2_type, "host" => $node->v2_host, "path" => $node->v2_path, "tls" => $node->v2_tls == 1? "tls" : ""];
+				$v2_scheme = 'vmess://'.base64_encode(json_encode($v2_json, JSON_PRETTY_PRINT));
+
+				// 生成文本配置信息
+				$txt = "服务器:".$node->server? : $node->ip.PHP_EOL;
+				if($node->ipv6){
+					$txt .= "IPv6:".$node->ipv6.PHP_EOL;
+				}
+				$txt .= "端口:".$node->v2_port.PHP_EOL;
+				$txt .= "加密方式:".$node->v2_method.PHP_EOL;
+				$txt .= "用户ID:".Auth::user()->vmess_id.PHP_EOL;
+				$txt .= "额外ID:".$node->v2_alter_id.PHP_EOL;
+				$txt .= "传输协议:".$node->v2_net.PHP_EOL;
+				$txt .= "伪装类型:".$node->v2_type.PHP_EOL;
+				$txt .= $node->v2_host? "伪装域名:".$node->v2_host.PHP_EOL : "";
+				$txt .= $node->v2_path? "路径:".$node->v2_path.PHP_EOL : "";
+				$txt .= $node->v2_tls? "TLS:tls".PHP_EOL : "";
+
+				$node->txt = $txt;
+				$node->v2_scheme = $v2_scheme;
+			}
+
+			// 节点在线状态
+			$nodeInfo = SsNodeInfo::query()->where('node_id', $node->id)->where('log_time', '>=', strtotime("-10 minutes"))->orderBy('id', 'desc')->first();
+			$node->online_status = $nodeInfo? 1 : 0;
+
+			// 节点标签
+			$node->labels = SsNodeLabel::query()->with('labelInfo')->where('node_id', $node->id)->first();
+		}
+
+		$view['allNodes'] = rtrim($allNodes, "|");
+		$view['nodeList'] = $nodeList;
+
+		return Response::view('user.nodeList', $view);
+	}
+
+	// 公告详情
+	public function article(Request $request)
+	{
+		$view['info'] = Article::query()->findOrFail($request->id);
+
+		return Response::view('user.article', $view);
+	}
+
+	// 修改个人资料
+	public function profile(Request $request)
+	{
+		if($request->isMethod('POST')){
+			$old_password = trim($request->input('old_password'));
+			$new_password = trim($request->input('new_password'));
+			$wechat = $request->input('wechat');
+			$qq = $request->input('qq');
+			$passwd = trim($request->input('passwd'));
+
+			// 修改密码
+			if($old_password && $new_password){
+				if(!Hash::check($old_password, Auth::user()->password)){
+					return Redirect::to('profile#tab_1')->withErrors('旧密码错误,请重新输入');
+				}elseif(Hash::check($new_password, Auth::user()->password)){
+					return Redirect::to('profile#tab_1')->withErrors('新密码不可与旧密码一样,请重新输入');
+				}
+
+				// 演示环境禁止改管理员密码
+				if(env('APP_DEMO') && Auth::user()->id == 1){
+					return Redirect::to('profile#tab_1')->withErrors('演示环境禁止修改管理员密码');
+				}
+
+				$ret = User::uid()->update(['password' => Hash::make($new_password)]);
+				if(!$ret){
+					return Redirect::to('profile#tab_1')->withErrors('修改失败');
+				}else{
+					return Redirect::to('profile#tab_1')->with('successMsg', '修改成功');
+				}
+			}
+
+			// 修改联系方式
+			if($wechat || $qq){
+				if(empty(clean($wechat)) && empty(clean($qq))){
+					return Redirect::to('profile#tab_2')->withErrors('修改失败');
+				}
+
+				$ret = User::uid()->update(['wechat' => $wechat, 'qq' => $qq]);
+				if(!$ret){
+					return Redirect::to('profile#tab_2')->withErrors('修改失败');
+				}else{
+					return Redirect::to('profile#tab_2')->with('successMsg', '修改成功');
+				}
+			}
+
+			// 修改代理密码
+			if($passwd){
+				$ret = User::uid()->update(['passwd' => $passwd]);
+				if(!$ret){
+					return Redirect::to('profile#tab_3')->withErrors('修改失败');
+				}else{
+					return Redirect::to('profile#tab_3')->with('successMsg', '修改成功');
+				}
+			}
+
+			return Redirect::to('profile#tab_1')->withErrors('非法请求');
+		}else{
+			return Response::view('user.profile');
+		}
+	}
+
+	// 商品列表
+	public function services(Request $request)
+	{
+		// 余额充值商品,只取10个
+		$view['chargeGoodsList'] = Goods::type(3)->where('status', 1)->orderBy('price', 'asc')->orderBy('price', 'asc')->limit(10)->get();
+		$view['goodsList'] = Goods::query()->where('status', 1)->where('type', '<=', '2')->orderBy('type', 'desc')->orderBy('sort', 'desc')->paginate(10)->appends($request->except('page'));
+
+		return Response::view('user.services', $view);
+	}
+
+	// 工单
+	public function ticketList(Request $request)
+	{
+		$view['ticketList'] = Ticket::uid()->orderBy('id', 'desc')->paginate(10)->appends($request->except('page'));
+
+		return Response::view('user.ticketList', $view);
+	}
+
+	// 订单
+	public function invoices(Request $request)
+	{
+		$view['orderList'] = Order::uid()->with(['user', 'goods', 'coupon', 'payment'])->orderBy('oid', 'desc')->paginate(10)->appends($request->except('page'));
+
+		return Response::view('user.invoices', $view);
+	}
+
+	// 订单明细
+	public function invoiceDetail(Request $request, $sn)
+	{
+		$view['order'] = Order::uid()->with(['goods', 'coupon', 'payment'])->where('order_sn', $sn)->firstOrFail();
+
+		return Response::view('user.invoiceDetail', $view);
+	}
+
+	// 添加工单
+	public function addTicket(Request $request)
+	{
+		$title = $request->input('title');
+		$content = clean($request->input('content'));
+		$content = str_replace("eval", "", str_replace("atob", "", $content));
+
+		if(empty($title) || empty($content)){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '请输入标题和内容']);
+		}
+
+		$obj = new Ticket();
+		$obj->user_id = Auth::user()->id;
+		$obj->title = $title;
+		$obj->content = $content;
+		$obj->status = 0;
+		$obj->save();
+
+		if($obj->id){
+			$emailTitle = "新工单提醒";
+			$content = "标题:【".$title."】<br>用户:".Auth::user()->username."<br>内容:".$content;
+
+			// 发邮件通知管理员
+			if(self::$systemConfig['crash_warning_email']){
+				$logId = Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], $emailTitle, $content);
+				Mail::to(self::$systemConfig['crash_warning_email'])->send(new newTicket($logId, $emailTitle, $content));
+			}
+
+			ServerChan::send($emailTitle, $content);
+
+			return Response::json(['status' => 'success', 'data' => '', 'message' => '提交成功']);
+		}else{
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '提交失败']);
+		}
+	}
+
+	// 回复工单
+	public function replyTicket(Request $request)
+	{
+		$id = $request->input('id');
+
+		$ticket = Ticket::uid()->with('user')->where('id', $id)->firstOrFail();
+
+		if($request->isMethod('POST')){
+			$content = clean($request->input('content'));
+			$content = str_replace("eval", "", str_replace("atob", "", $content));
+			$content = substr($content, 0, 300);
+
+			if(empty($content)){
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '回复内容不能为空']);
+			}
+
+			if($ticket->status == 2){
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '错误:该工单已关闭']);
+			}
+
+			$obj = new TicketReply();
+			$obj->ticket_id = $id;
+			$obj->user_id = Auth::user()->id;
+			$obj->content = $content;
+			$obj->save();
+
+			if($obj->id){
+				// 重新打开工单
+				$ticket->status = 0;
+				$ticket->save();
+
+				$title = "工单回复提醒";
+				$content = "标题:【".$ticket->title."】<br>用户回复:".$content;
+
+				// 发邮件通知管理员
+				if(self::$systemConfig['crash_warning_email']){
+					$logId = Helpers::addEmailLog(self::$systemConfig['crash_warning_email'], $title, $content);
+					Mail::to(self::$systemConfig['crash_warning_email'])->send(new replyTicket($logId, $title, $content));
+				}
+
+				ServerChan::send($title, $content);
+
+				return Response::json(['status' => 'success', 'data' => '', 'message' => '回复成功']);
+			}else{
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '回复失败']);
+			}
+		}else{
+			$view['ticket'] = $ticket;
+			$view['replyList'] = TicketReply::query()->where('ticket_id', $id)->with('user')->orderBy('id', 'asc')->get();
+
+			return Response::view('user.replyTicket', $view);
+		}
+	}
+
+	// 关闭工单
+	public function closeTicket(Request $request)
+	{
+		$id = $request->input('id');
+
+		$ret = Ticket::uid()->where('id', $id)->update(['status' => 2]);
+		if($ret){
+			ServerChan::send('工单关闭提醒', '工单:ID'.$id.'用户已手动关闭');
+
+			return Response::json(['status' => 'success', 'data' => '', 'message' => '关闭成功']);
+		}else{
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '关闭失败']);
+		}
+	}
+
+	// 邀请码
+	public function invite(Request $request)
+	{
+		if(Order::uid()->where('status', 2)->where('is_expire', 0)->where('origin_amount', '>', 0)->get()->isEmpty()){
+			return Response::view('auth.error', ['message' => '本功能对非付费用户禁用!请 <a class="btn btn-sm btn-danger" href="/">返回</a>']);
+		}
+		// 已生成的邀请码数量
+		$num = Invite::uid()->count();
+
+		$view['num'] = self::$systemConfig['invite_num']-$num <= 0? 0 : self::$systemConfig['invite_num']-$num; // 还可以生成的邀请码数量
+		$view['inviteList'] = Invite::uid()->with(['generator', 'user'])->paginate(10); // 邀请码列表
+		$view['referral_traffic'] = flowAutoShow(self::$systemConfig['referral_traffic']*1048576);
+		$view['referral_percent'] = self::$systemConfig['referral_percent'];
+
+		return Response::view('user.invite', $view);
+	}
+
+	// 生成邀请码
+	public function makeInvite(Request $request)
+	{
+		// 已生成的邀请码数量
+		$num = Invite::uid()->count();
+		if($num >= self::$systemConfig['invite_num']){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '生成失败:最多只能生成'.self::$systemConfig['invite_num'].'个邀请码']);
+		}
+
+		$obj = new Invite();
+		$obj->uid = Auth::user()->id;
+		$obj->fuid = 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::$systemConfig['user_invite_days']." days"));
+		$obj->save();
+
+		return Response::json(['status' => 'success', 'data' => '', 'message' => '生成成功']);
+	}
+
+	// 使用优惠券
+	public function redeemCoupon(Request $request)
+	{
+		$coupon_sn = $request->input('coupon_sn');
+
+		if(empty($coupon_sn)){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '优惠券不能为空']);
+		}
+
+		$coupon = Coupon::query()->where('sn', $coupon_sn)->whereIn('type', [1, 2])->first();
+		if(!$coupon){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '该优惠券不存在']);
+		}elseif($coupon->status == 1){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '该优惠券已使用,请换一个试试']);
+		}elseif($coupon->status == 2){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '该优惠券已失效,请换一个试试']);
+		}elseif($coupon->available_end < time()){
+			$coupon->status = 2;
+			$coupon->save();
+
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '该优惠券已失效,请换一个试试']);
+		}elseif($coupon->available_start > time()){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '该优惠券尚不可用,请换一个试试']);
+		}
+
+		$data = ['name' => $coupon->name, 'type' => $coupon->type, 'amount' => $coupon->amount, 'discount' => $coupon->discount];
+
+		return Response::json(['status' => 'success', 'data' => $data, 'message' => '优惠券有效']);
+	}
+
+	// 购买服务
+	public function buy(Request $request, $goods_id)
+	{
+		$coupon_sn = $request->input('coupon_sn');
+		// 余额支付
+		if($request->isMethod('POST')){
+			$goods = Goods::query()->with(['label'])->where('status', 1)->where('id', $goods_id)->first();
+			if(!$goods){
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:商品或服务已下架']);
+			}
+
+			// 限购控制:all-所有商品限购, free-价格为0的商品限购, none-不限购(默认)
+			$strategy = self::$systemConfig['goods_purchase_limit_strategy'];
+			if($strategy == 'all' || ($strategy == 'package' && $goods->type == 2) || ($strategy == 'free' && $goods->price == 0) || ($strategy == 'package&free' && ($goods->type == 2 || $goods->price == 0))){
+				$noneExpireGoodExist = Order::uid()->where('status', '>=', 0)->where('is_expire', 0)->where('goods_id', $goods_id)->exists();
+				if($noneExpireGoodExist){
+					return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:商品不可重复购买']);
+				}
+			}
+
+			// 单个商品限购
+			if($goods->is_limit == 1){
+				$noneExpireOrderExist = Order::uid()->where('status', '>=', 0)->where('goods_id', $goods_id)->exists();
+				if($noneExpireOrderExist){
+					return Response::json(['status' => 'fail', 'data' => '', 'message' => '创建支付单失败:此商品每人限购1次']);
+				}
+			}
+
+			// 使用优惠券
+			if(!empty($coupon_sn)){
+				$coupon = Coupon::query()->where('status', 0)->whereIn('type', [1, 2])->where('sn', $coupon_sn)->first();
+				if(!$coupon){
+					return Response::json(['status' => 'fail', 'data' => '', 'message' => '优惠券不存在']);
+				}
+
+				// 计算实际应支付总价
+				$amount = $coupon->type == 2? $goods->price*$coupon->discount/10 : $goods->price-$coupon->amount;
+				$amount = $amount > 0? $amount : 0;
+			}else{
+				$amount = $goods->price;
+			}
+
+			// 价格异常判断
+			if($amount < 0){
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:订单总价异常']);
+			}
+
+			// 验证账号余额是否充足
+			if(Auth::user()->balance < $amount){
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:您的余额不足,请先充值']);
+			}
+
+			// 验证账号是否存在有效期更长的套餐
+			if($goods->type == 2){
+				$existOrderList = Order::uid()->with('goods')->whereHas('goods', function($q){
+					$q->where('type', 2);
+				})->where('is_expire', 0)->where('status', 2)->get();
+
+				foreach($existOrderList as $vo){
+					if($vo->goods->days > $goods->days){
+						return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:您已存在有效期更长的套餐,只能购买流量包']);
+					}
+				}
+			}
+
+			DB::beginTransaction();
+			try{
+				// 生成订单
+				$order = new Order();
+				$order->order_sn = date('ymdHis').mt_rand(100000, 999999);
+				$order->user_id = Auth::user()->id;
+				$order->goods_id = $goods_id;
+				$order->coupon_id = !empty($coupon)? $coupon->id : 0;
+				$order->origin_amount = $goods->price;
+				$order->amount = $amount;
+				$order->expire_at = date("Y-m-d H:i:s", strtotime("+".$goods->days." days"));
+				$order->is_expire = 0;
+				$order->pay_way = 1;
+				$order->status = 2;
+				$order->save();
+
+				// 扣余额
+				User::query()->where('id', Auth::user()->id)->decrement('balance', $amount*100);
+
+				// 记录余额操作日志
+				$this->addUserBalanceLog(Auth::user()->id, $order->oid, Auth::user()->balance, Auth::user()->balance-$amount, -1*$amount, '购买商品:'.$goods->name);
+
+				// 优惠券置为已使用
+				if(!empty($coupon)){
+					if($coupon->usage == 1){
+						$coupon->status = 1;
+						$coupon->save();
+					}
+
+					// 写入日志
+					Helpers::addCouponLog($coupon->id, $goods_id, $order->oid, '余额支付订单使用');
+				}
+
+				// 如果买的是套餐,则先将之前购买的所有套餐置都无效,并扣掉之前所有套餐的流量,重置用户已用流量为0
+				if($goods->type == 2){
+					$existOrderList = Order::query()->with('goods')->whereHas('goods', function($q){
+						$q->where('type', 2);
+					})->where('user_id', Auth::user()->id)->where('oid', '<>', $order->oid)->where('is_expire', 0)->where('status', 2)->get();
+
+					foreach($existOrderList as $vo){
+						Order::query()->where('oid', $vo->oid)->update(['is_expire' => 1]);
+
+						// 先判断,防止手动扣减过流量的用户流量被扣成负数
+						if($order->user->transfer_enable-$vo->goods->traffic*1048576 <= 0){
+							// 写入用户流量变动记录
+							Helpers::addUserTrafficModifyLog(Auth::user()->id, $order->oid, 0, 0, '[余额支付]用户购买套餐,先扣减之前套餐的流量(扣完)');
+
+							User::query()->where('id', Auth::user()->id)->update(['u' => 0, 'd' => 0, 'transfer_enable' => 0]);
+						}else{
+							// 写入用户流量变动记录
+							$user = User::query()->uid()->first(); // 重新取出user信息
+							Helpers::addUserTrafficModifyLog(Auth::user()->id, $order->oid, $user->transfer_enable, ($user->transfer_enable-$vo->goods->traffic*1048576), '[余额支付]用户购买套餐,先扣减之前套餐的流量(未扣完)');
+
+							User::query()->uid()->update(['u' => 0, 'd' => 0]);
+							User::query()->uid()->decrement('transfer_enable', $vo->goods->traffic*1048576);
+						}
+					}
+				}
+
+				// 写入用户流量变动记录
+				$user = User::query()->uid()->first(); // 重新取出user信息
+				Helpers::addUserTrafficModifyLog($user->id, $order->oid, $user->transfer_enable, ($user->transfer_enable+$goods->traffic*1048576), '[余额支付]用户购买商品,加上流量');
+
+				// 把商品的流量加到账号上
+				User::query()->where('id', $user->id)->increment('transfer_enable', $goods->traffic*1048576);
+
+				// 计算账号过期时间
+				if($user->expire_time < date('Y-m-d', strtotime("+".$goods->days." days"))){
+					$expireTime = date('Y-m-d', strtotime("+".$goods->days." days"));
+				}else{
+					$expireTime = $user->expire_time;
+				}
+
+				// 套餐就改流量重置日,流量包不改
+				if($goods->type == 2){
+					$traffic_reset_day = date('d');
+					User::query()->uid()->update(['traffic_reset_day' => $traffic_reset_day, 'expire_time' => $expireTime, 'enable' => 1]);
+				}else{
+					User::query()->uid()->update(['expire_time' => $expireTime, 'enable' => 1]);
+				}
+
+				// 写入用户标签
+				if($goods->label){
+					// 用户默认标签
+					$defaultLabels = [];
+					if(self::$systemConfig['initial_labels_for_user']){
+						$defaultLabels = explode(',', self::$systemConfig['initial_labels_for_user']);
+					}
+
+					// 取出现有的标签
+					$userLabels = UserLabel::query()->where('user_id', Auth::user()->id)->pluck('label_id')->toArray();
+					$goodsLabels = GoodsLabel::query()->where('goods_id', $goods_id)->pluck('label_id')->toArray();
+
+					// 标签去重
+					$newUserLabels = array_values(array_unique(array_merge($userLabels, $goodsLabels, $defaultLabels)));
+
+					// 删除用户所有标签
+					UserLabel::query()->where('user_id', Auth::user()->id)->delete();
+
+					// 生成标签
+					foreach($newUserLabels as $vo){
+						$obj = new UserLabel();
+						$obj->user_id = Auth::user()->id;
+						$obj->label_id = $vo;
+						$obj->save();
+					}
+				}
+
+				// 写入返利日志
+				if($user->referral_uid){
+					$this->addReferralLog($user->id, $user->referral_uid, $order->oid, $amount, $amount*self::$systemConfig['referral_percent']);
+				}
+
+				// 取消重复返利
+				User::query()->where('id', $order->user_id)->update(['referral_uid' => 0]);
+
+				DB::commit();
+
+				return Response::json(['status' => 'success', 'data' => '', 'message' => '支付成功']);
+			} catch(Exception $e){
+				Log::error('支付订单失败:'.$e);
+
+				DB::rollBack();
+
+				return Response::json(['status' => 'fail', 'data' => '', 'message' => '支付失败:'.$e->getMessage()]);
+			}
+		}else{
+			$goods = Goods::query()->where('id', $goods_id)->where('status', 1)->first();
+			if(empty($goods)){
+				return Redirect::to('services');
+			}
+
+			$view['goods'] = $goods;
+
+			return Response::view('user.buy', $view);
+		}
+	}
+
+	// 推广返利
+	public function referral(Request $request)
+	{
+		if(Order::uid()->where('status', 2)->where('is_expire', 0)->where('origin_amount', '>', 0)->get()->isEmpty()){
+			return Response::view('auth.error', ['message' => '本功能对非付费用户禁用!请 <a class="btn btn-sm btn-danger" href="/">返回</a>']);
+		}
+		$view['referral_traffic'] = flowAutoShow(self::$systemConfig['referral_traffic']*1048576);
+		$view['referral_percent'] = self::$systemConfig['referral_percent'];
+		$view['referral_money'] = self::$systemConfig['referral_money'];
+		$view['totalAmount'] = ReferralLog::uid()->sum('ref_amount')/100;
+		$view['canAmount'] = ReferralLog::uid()->where('status', 0)->sum('ref_amount')/100;
+		$view['link'] = self::$systemConfig['website_url'].'/register?aff='.Auth::user()->id;
+		$view['referralLogList'] = ReferralLog::uid()->with('user')->orderBy('id', 'desc')->paginate(10, ['*'], 'log_page');
+		$view['referralApplyList'] = ReferralApply::uid()->with('user')->orderBy('id', 'desc')->paginate(10, ['*'], 'apply_page');
+		$view['referralUserList'] = User::query()->select(['username', 'created_at'])->where('referral_uid', Auth::user()->id)->orderBy('id', 'desc')->paginate(10, ['*'], 'user_page');
+
+		return Response::view('user.referral', $view);
+	}
+
+	// 申请提现
+	public function extractMoney(Request $request)
+	{
+		// 判断账户是否过期
+		if(Auth::user()->expire_time < date('Y-m-d')){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '申请失败:账号已过期,请先购买服务吧']);
+		}
+
+		// 判断是否已存在申请
+		$referralApply = ReferralApply::uid()->whereIn('status', [0, 1])->first();
+		if($referralApply){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '申请失败:已存在申请,请等待之前的申请处理完']);
+		}
+
+		// 校验可以提现金额是否超过系统设置的阀值
+		$ref_amount = ReferralLog::uid()->where('status', 0)->sum('ref_amount');
+		$ref_amount = $ref_amount/100;
+		if($ref_amount < self::$systemConfig['referral_money']){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '申请失败:满'.self::$systemConfig['referral_money'].'元才可以提现,继续努力吧']);
+		}
+
+		// 取出本次申请关联返利日志ID
+		$link_logs = '';
+		$referralLog = ReferralLog::uid()->where('status', 0)->get();
+		foreach($referralLog as $log){
+			$link_logs .= $log->id.',';
+		}
+		$link_logs = rtrim($link_logs, ',');
+
+		$obj = new ReferralApply();
+		$obj->user_id = Auth::user()->id;
+		$obj->before = $ref_amount;
+		$obj->after = 0;
+		$obj->amount = $ref_amount;
+		$obj->link_logs = $link_logs;
+		$obj->status = 0;
+		$obj->save();
+
+		return Response::json(['status' => 'success', 'data' => '', 'message' => '申请成功,请等待管理员审核']);
+	}
+
+	// 帮助中心
+	public function help(Request $request)
+	{
+		$view['articleList'] = Article::type(1)->orderBy('sort', 'desc')->orderBy('id', 'desc')->limit(10)->paginate(5);
+
+		//付费用户判断
+		$view['not_paying_user'] = Order::uid()->where('status', 2)->where('is_expire', 0)->where('origin_amount', '>', 0)->get()->isEmpty();
+		//客户端安装
+		$view['Shadowrocket_install'] = 'itms-services://?action=download-manifest&url='.self::$systemConfig['website_url'].'/clients/ipa.plist';
+		$view['Quantumult_install'] = 'itms-services://?action=download-manifest&url='.self::$systemConfig['website_url'].'/ipa.plist';
+		// 订阅连接
+		$subscribe = UserSubscribe::query()->where('user_id', Auth::user()->id)->first();
+		$view['subscribe_status'] = $subscribe->status;
+		$subscribe_link = (self::$systemConfig['subscribe_domain']? self::$systemConfig['subscribe_domain'] : self::$systemConfig['website_url']).'/s/'.$subscribe->code;
+		$view['link'] = $subscribe_link;
+		$view['Shadowrocket_link'] = 'shadowrocket://add/sub://'.base64url_encode($subscribe_link).'?remarks='.self::$systemConfig['website_name'].'-'.self::$systemConfig['website_url'];
+		$view['Shadowrocket_linkQrcode'] = 'sub://'.base64url_encode($subscribe_link).'#'.base64url_encode(self::$systemConfig['website_name']);
+		$view['Quantumult_linkOut'] = 'quantumult://configuration?server='.base64url_encode($subscribe_link).'&filter='.base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/Pro.conf').'&rejection='.base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/Rejection.conf');
+		$view['Quantumult_linkIn'] = 'quantumult://configuration?server='.base64url_encode($subscribe_link).'&filter='.base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/BacktoCN.conf').'&rejection='.base64url_encode('https://raw.githubusercontent.com/ConnersHua/Profiles/master/Quantumult/Rejection.conf');
+
+		return Response::view('user.help', $view);
+	}
+
+	// 更换订阅地址
+	public function exchangeSubscribe(Request $request)
+	{
+		DB::beginTransaction();
+		try{
+			// 更换订阅码
+			UserSubscribe::uid()->update(['code' => Helpers::makeSubscribeCode()]);
+
+			// 更换连接密码
+			User::uid()->update(['passwd' => makeRandStr()]);
+
+			DB::commit();
+
+			return Response::json(['status' => 'success', 'data' => '', 'message' => '更换成功']);
+		} catch(Exception $e){
+			DB::rollBack();
+
+			Log::info("更换订阅地址异常:".$e->getMessage());
+
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '更换失败'.$e->getMessage()]);
+		}
+	}
+
+	// 转换成管理员的身份
+	public function switchToAdmin(Request $request)
+	{
+		if(!Session::has('admin')){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '非法请求']);
+		}
+
+		// 管理员信息重新写入user
+		Auth::loginUsingId(Session::get('admin'));
+		Session::forget('admin');
+
+		return Response::json(['status' => 'success', 'data' => '', 'message' => "身份切换成功"]);
+	}
+
+	// 卡券余额充值
+	public function charge(Request $request)
+	{
+		$validator = Validator::make($request->all(), ['coupon_sn' => ['required', Rule::exists('coupon', 'sn')->where(function($query){
+			$query->where('type', 3)->where('status', 0);
+		}),]], ['coupon_sn.required' => '券码不能为空', 'coupon_sn.exists' => '该券不可用']);
+
+		if($validator->fails()){
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => $validator->getMessageBag()->first()]);
+		}
+
+		$coupon = Coupon::query()->where('sn', $request->input('coupon_sn'))->first();
+
+		DB::beginTransaction();
+		try{
+			// 写入日志
+			$this->addUserBalanceLog(Auth::user()->id, 0, Auth::user()->balance, Auth::user()->balance+$coupon->amount, $coupon->amount, '用户手动充值 - [充值券:'.$request->input('coupon_sn').']');
+
+			// 余额充值
+			User::uid()->increment('balance', $coupon->amount*100);
+
+			// 更改卡券状态
+			$coupon->status = 1;
+			$coupon->save();
+
+			// 写入卡券日志
+			Helpers::addCouponLog($coupon->id, 0, 0, '账户余额充值使用');
+
+			DB::commit();
+
+			return Response::json(['status' => 'success', 'data' => '', 'message' => '充值成功']);
+		} catch(Exception $e){
+			Log::error($e);
+			DB::rollBack();
+
+			return Response::json(['status' => 'fail', 'data' => '', 'message' => '充值失败']);
+		}
+	}
 }

+ 81 - 57
app/Http/Kernel.php

@@ -2,69 +2,93 @@
 
 namespace App\Http;
 
+use App\Http\Middleware\Affiliate;
+use App\Http\Middleware\CheckForMaintenanceMode;
+use App\Http\Middleware\EncryptCookies;
+use App\Http\Middleware\isAdmin;
+use App\Http\Middleware\isForbidden;
+use App\Http\Middleware\isLogin;
+use App\Http\Middleware\isSecurity;
+use App\Http\Middleware\RedirectIfAuthenticated;
+use App\Http\Middleware\SetLocale;
+use App\Http\Middleware\TrimStrings;
+use App\Http\Middleware\TrustProxies;
+use App\Http\Middleware\VerifyCsrfToken;
+use Illuminate\Auth\Middleware\Authenticate;
+use Illuminate\Auth\Middleware\AuthenticateWithBasicAuth;
+use Illuminate\Auth\Middleware\Authorize;
+use Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse;
 use Illuminate\Foundation\Http\Kernel as HttpKernel;
+use Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull;
+use Illuminate\Foundation\Http\Middleware\ValidatePostSize;
+use Illuminate\Http\Middleware\SetCacheHeaders;
+use Illuminate\Routing\Middleware\SubstituteBindings;
+use Illuminate\Routing\Middleware\ThrottleRequests;
+use Illuminate\Routing\Middleware\ValidateSignature;
+use Illuminate\Session\Middleware\StartSession;
+use Illuminate\View\Middleware\ShareErrorsFromSession;
 
 class Kernel extends HttpKernel
 {
-    /**
-     * The application's global HTTP middleware stack.
-     *
-     * These middleware are run during every request to your application.
-     *
-     * @var array
-     */
-    protected $middleware = [
-        \App\Http\Middleware\CheckForMaintenanceMode::class,
-        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
-        \App\Http\Middleware\TrimStrings::class,
-        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
-        \App\Http\Middleware\TrustProxies::class,
-    ];
+	/**
+	 * The application's global HTTP middleware stack.
+	 *
+	 * These middleware are run during every request to your application.
+	 *
+	 * @var array
+	 */
+	protected $middleware = [
+		CheckForMaintenanceMode::class,
+		ValidatePostSize::class,
+		TrimStrings::class,
+		ConvertEmptyStringsToNull::class,
+		TrustProxies::class,
+	];
 
-    /**
-     * The application's route middleware groups.
-     *
-     * @var array
-     */
-    protected $middlewareGroups = [
-        'web' => [
-            \App\Http\Middleware\EncryptCookies::class,
-            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
-            \Illuminate\Session\Middleware\StartSession::class,
-            // \Illuminate\Session\Middleware\AuthenticateSession::class,
-            \App\Http\Middleware\SetLocale::class,
-            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
-            \App\Http\Middleware\VerifyCsrfToken::class,
-            \Illuminate\Routing\Middleware\SubstituteBindings::class,
-        ],
+	/**
+	 * The application's route middleware groups.
+	 *
+	 * @var array
+	 */
+	protected $middlewareGroups = [
+		'web' => [
+			EncryptCookies::class,
+			AddQueuedCookiesToResponse::class,
+			StartSession::class,
+			// \Illuminate\Session\Middleware\AuthenticateSession::class,
+			SetLocale::class,
+			ShareErrorsFromSession::class,
+			VerifyCsrfToken::class,
+			SubstituteBindings::class,
+		],
 
-        'api' => [
-            'throttle:60,1',
-            'bindings',
-        ],
-    ];
+		'api' => [
+			'throttle:60,1',
+			'bindings',
+		],
+	];
 
-    /**
-     * The application's route middleware.
-     *
-     * These middleware may be assigned to groups or used individually.
-     *
-     * @var array
-     */
-    protected $routeMiddleware = [
-        'auth'          => \Illuminate\Auth\Middleware\Authenticate::class,
-        'auth.basic'    => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
-        'bindings'      => \Illuminate\Routing\Middleware\SubstituteBindings::class,
-        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
-        'can'           => \Illuminate\Auth\Middleware\Authorize::class,
-        'guest'         => \App\Http\Middleware\RedirectIfAuthenticated::class,
-        'signed'        => \Illuminate\Routing\Middleware\ValidateSignature::class,
-        'throttle'      => \Illuminate\Routing\Middleware\ThrottleRequests::class,
-        'isAdmin'       => \App\Http\Middleware\isAdmin::class,
-        'isLogin'       => \App\Http\Middleware\isLogin::class,
-        'isSecurity'    => \App\Http\Middleware\isSecurity::class,
-        'isForbidden'   => \App\Http\Middleware\isForbidden::class,
-        'affiliate'     => \App\Http\Middleware\Affiliate::class,
+	/**
+	 * The application's route middleware.
+	 *
+	 * These middleware may be assigned to groups or used individually.
+	 *
+	 * @var array
+	 */
+	protected $routeMiddleware = [
+		'auth'          => Authenticate::class,
+		'auth.basic'    => AuthenticateWithBasicAuth::class,
+		'bindings'      => SubstituteBindings::class,
+		'cache.headers' => SetCacheHeaders::class,
+		'can'           => Authorize::class,
+		'guest'         => RedirectIfAuthenticated::class,
+		'signed'        => ValidateSignature::class,
+		'throttle'      => ThrottleRequests::class,
+		'isAdmin'       => isAdmin::class,
+		'isLogin'       => isLogin::class,
+		'isSecurity'    => isSecurity::class,
+		'isForbidden'   => isForbidden::class,
+		'affiliate'     => Affiliate::class,
 
-    ];
+	];
 }

+ 18 - 17
app/Http/Middleware/Affiliate.php

@@ -2,26 +2,27 @@
 
 namespace App\Http\Middleware;
 
-use Cookie;
 use Closure;
+use Cookie;
+use Illuminate\Http\Request;
 
 class Affiliate
 {
-    /**
-     * 返利识别
-     *
-     * @param  \Illuminate\Http\Request $request
-     * @param  \Closure                 $next
-     *
-     * @return mixed
-     */
-    public function handle($request, Closure $next)
-    {
-        $aff = trim($request->input('aff', 0));
-        if ($aff) {
-            Cookie::queue('register_aff', $aff, 129600);
-        }
+	/**
+	 * 返利识别
+	 *
+	 * @param Request $request
+	 * @param Closure                  $next
+	 *
+	 * @return mixed
+	 */
+	public function handle($request, Closure $next)
+	{
+		$aff = trim($request->input('aff', 0));
+		if($aff){
+			Cookie::queue('register_aff', $aff, 129600);
+		}
 
-        return $next($request);
-    }
+		return $next($request);
+	}
 }

+ 8 - 8
app/Http/Middleware/CheckForMaintenanceMode.php

@@ -6,12 +6,12 @@ use Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode as Middleware;
 
 class CheckForMaintenanceMode extends Middleware
 {
-    /**
-     * The URIs that should be reachable while maintenance mode is enabled.
-     *
-     * @var array
-     */
-    protected $except = [
-        //
-    ];
+	/**
+	 * The URIs that should be reachable while maintenance mode is enabled.
+	 *
+	 * @var array
+	 */
+	protected $except = [
+		//
+	];
 }

+ 8 - 8
app/Http/Middleware/EncryptCookies.php

@@ -6,12 +6,12 @@ use Illuminate\Cookie\Middleware\EncryptCookies as Middleware;
 
 class EncryptCookies extends Middleware
 {
-    /**
-     * The names of the cookies that should not be encrypted.
-     *
-     * @var array
-     */
-    protected $except = [
-        //
-    ];
+	/**
+	 * The names of the cookies that should not be encrypted.
+	 *
+	 * @var array
+	 */
+	protected $except = [
+		//
+	];
 }

+ 17 - 16
app/Http/Middleware/RedirectIfAuthenticated.php

@@ -3,24 +3,25 @@
 namespace App\Http\Middleware;
 
 use Closure;
+use Illuminate\Http\Request;
 
 class RedirectIfAuthenticated
 {
-    /**
-     * Handle an incoming request.
-     *
-     * @param  \Illuminate\Http\Request $request
-     * @param  \Closure                 $next
-     * @param  string|null              $guard
-     *
-     * @return mixed
-     */
-    public function handle($request, Closure $next, $guard = null)
-    {
-        if (auth()->guard($guard)->check()) {
-            return redirect('/');
-        }
+	/**
+	 * Handle an incoming request.
+	 *
+	 * @param Request $request
+	 * @param Closure                  $next
+	 * @param string|null              $guard
+	 *
+	 * @return mixed
+	 */
+	public function handle($request, Closure $next, $guard = NULL)
+	{
+		if(auth()->guard($guard)->check()){
+			return redirect('/');
+		}
 
-        return $next($request);
-    }
+		return $next($request);
+	}
 }

+ 20 - 19
app/Http/Middleware/SetLocale.php

@@ -3,30 +3,31 @@
 namespace App\Http\Middleware;
 
 use Closure;
+use Illuminate\Http\Request;
 use Session;
 
 class SetLocale
 {
-    /**
-     * 变更语言
-     *
-     * @param  \Illuminate\Http\Request $request
-     * @param  \Closure                 $next
-     *
-     * @return mixed
-     */
-    public function handle($request, Closure $next)
-    {
-        if (Session::has('locale')) {
-            app()->setLocale(Session::get('locale'));
-        }
+	/**
+	 * 变更语言
+	 *
+	 * @param Request $request
+	 * @param Closure                  $next
+	 *
+	 * @return mixed
+	 */
+	public function handle($request, Closure $next)
+	{
+		if(Session::has('locale')){
+			app()->setLocale(Session::get('locale'));
+		}
 
-        if ($request->query('locale')) {
-            Session::put('locale', $request->query('locale'));
-            app()->setLocale($request->query('locale'));
-        }
+		if($request->query('locale')){
+			Session::put('locale', $request->query('locale'));
+			app()->setLocale($request->query('locale'));
+		}
 
-        return $next($request);
-    }
+		return $next($request);
+	}
 
 }

+ 9 - 9
app/Http/Middleware/TrimStrings.php

@@ -6,13 +6,13 @@ use Illuminate\Foundation\Http\Middleware\TrimStrings as Middleware;
 
 class TrimStrings extends Middleware
 {
-    /**
-     * The names of the attributes that should not be trimmed.
-     *
-     * @var array
-     */
-    protected $except = [
-        'password',
-        'password_confirmation',
-    ];
+	/**
+	 * The names of the attributes that should not be trimmed.
+	 *
+	 * @var array
+	 */
+	protected $except = [
+		'password',
+		'password_confirmation',
+	];
 }

+ 13 - 13
app/Http/Middleware/TrustProxies.php

@@ -2,22 +2,22 @@
 
 namespace App\Http\Middleware;
 
-use Illuminate\Http\Request;
 use Fideloper\Proxy\TrustProxies as Middleware;
+use Illuminate\Http\Request;
 
 class TrustProxies extends Middleware
 {
-    /**
-     * The trusted proxies for this application.
-     *
-     * @var array
-     */
-    protected $proxies;
+	/**
+	 * The trusted proxies for this application.
+	 *
+	 * @var array
+	 */
+	protected $proxies;
 
-    /**
-     * The headers that should be used to detect proxies.
-     *
-     * @var string
-     */
-    protected $headers = Request::HEADER_X_FORWARDED_ALL;
+	/**
+	 * The headers that should be used to detect proxies.
+	 *
+	 * @var string
+	 */
+	protected $headers = Request::HEADER_X_FORWARDED_ALL;
 }

+ 9 - 9
app/Http/Middleware/VerifyCsrfToken.php

@@ -6,13 +6,13 @@ use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
 
 class VerifyCsrfToken extends Middleware
 {
-    /**
-     * The URIs that should be excluded from CSRF verification.
-     *
-     * @var array
-     */
-    protected $except = [
-        "payment/*",
-        "checkIn"
-    ];
+	/**
+	 * The URIs that should be excluded from CSRF verification.
+	 *
+	 * @var array
+	 */
+	protected $except = [
+		"payment/*",
+		"checkIn"
+	];
 }

+ 16 - 15
app/Http/Middleware/isAdmin.php

@@ -4,24 +4,25 @@ namespace App\Http\Middleware;
 
 use Auth;
 use Closure;
+use Illuminate\Http\Request;
 use Redirect;
 
 class isAdmin
 {
-    /**
-     * 校验是否为管理员身份
-     *
-     * @param  \Illuminate\Http\Request $request
-     * @param  \Closure                 $next
-     *
-     * @return mixed
-     */
-    public function handle($request, Closure $next)
-    {
-        if (!Auth::user()->is_admin) {
-            return Redirect::to('/');
-        }
+	/**
+	 * 校验是否为管理员身份
+	 *
+	 * @param Request $request
+	 * @param Closure                  $next
+	 *
+	 * @return mixed
+	 */
+	public function handle($request, Closure $next)
+	{
+		if(!Auth::user()->is_admin){
+			return Redirect::to('/');
+		}
 
-        return $next($request);
-    }
+		return $next($request);
+	}
 }

+ 73 - 72
app/Http/Middleware/isForbidden.php

@@ -2,93 +2,94 @@
 
 namespace App\Http\Middleware;
 
+use Agent;
 use App\Components\Helpers;
 use App\Components\IPIP;
 use App\Components\QQWry;
-use Agent;
-use Log;
 use Closure;
+use Illuminate\Http\Request;
+use Log;
 
 class isForbidden
 {
-    /**
-     * 限制机器人、指定IP访问
-     *
-     * @param  \Illuminate\Http\Request $request
-     * @param  \Closure                 $next
-     *
-     * @return mixed
-     */
-    public function handle($request, Closure $next)
-    {
-        // 拒绝机器人访问
-        if (Helpers::systemConfig()['is_forbid_robot']) {
-            if (Agent::isRobot()) {
-                Log::info("识别到机器人访问(" . getClientIp() . ")");
+	/**
+	 * 限制机器人、指定IP访问
+	 *
+	 * @param Request $request
+	 * @param Closure                  $next
+	 *
+	 * @return mixed
+	 */
+	public function handle($request, Closure $next)
+	{
+		// 拒绝机器人访问
+		if(Helpers::systemConfig()['is_forbid_robot']){
+			if(Agent::isRobot()){
+				Log::info("识别到机器人访问(".getClientIp().")");
 
-                return response()->view('auth.error', ['message' => trans('error.ForbiddenRobot')], 404);
-            }
-        }
+				return response()->view('auth.error', ['message' => trans('error.ForbiddenRobot')], 404);
+			}
+		}
 
-        // 拒绝通过订阅链接域名访问网站,防止网站被探测
-        if (false !== strpos(Helpers::systemConfig()['subscribe_domain'], $request->getHost())) {
-            Log::info("识别到通过订阅链接访问,强制跳转至百度(" . getClientIp() . ")");
+		// 拒绝通过订阅链接域名访问网站,防止网站被探测
+		if(FALSE !== strpos(Helpers::systemConfig()['subscribe_domain'], $request->getHost())){
+			Log::info("识别到通过订阅链接访问,强制跳转至百度(".getClientIp().")");
 
-            return redirect('https://www.baidu.com');
-        }
+			return redirect('https://www.baidu.com');
+		}
 
-        $ip = getClientIP();
-        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) {
-            Log::info('识别到IPv6,尝试解析:' . $ip);
-            $isIPv6 = true;
-            $ipInfo = getIPv6($ip);
-        } else {
-            $isIPv6 = false;
-            $ipInfo = QQWry::ip($ip); // 通过纯真IP库解析IPv4信息
-            if (isset($ipInfo['error'])) {
-                Log::info('无法识别IPv4,尝试使用IPIP的IP库解析:' . $ip);
-                $ipip = IPIP::ip($ip);
-                $ipInfo = [
-                    'country'  => $ipip['country_name'],
-                    'province' => $ipip['region_name'],
-                    'city'     => $ipip['city_name']
-                ];
-            } else {
-                // 判断纯真IP库获取的国家信息是否与IPIP的IP库获取的信息一致,不一致则用IPIP的(因为纯真IP库的非大陆IP准确率较低)
-                $ipip = IPIP::ip($ip);
-                if ($ipInfo['country'] != $ipip['country_name']) {
-                    $ipInfo['country'] = $ipip['country_name'];
-                    $ipInfo['province'] = $ipip['region_name'];
-                    $ipInfo['city'] = $ipip['city_name'];
-                }
-            }
-        }
+		$ip = getClientIP();
+		if(filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)){
+			Log::info('识别到IPv6,尝试解析:'.$ip);
+			$isIPv6 = TRUE;
+			$ipInfo = getIPv6($ip);
+		}else{
+			$isIPv6 = FALSE;
+			$ipInfo = QQWry::ip($ip); // 通过纯真IP库解析IPv4信息
+			if(isset($ipInfo['error'])){
+				Log::info('无法识别IPv4,尝试使用IPIP的IP库解析:'.$ip);
+				$ipip = IPIP::ip($ip);
+				$ipInfo = [
+					'country'  => $ipip['country_name'],
+					'province' => $ipip['region_name'],
+					'city'     => $ipip['city_name']
+				];
+			}else{
+				// 判断纯真IP库获取的国家信息是否与IPIP的IP库获取的信息一致,不一致则用IPIP的(因为纯真IP库的非大陆IP准确率较低)
+				$ipip = IPIP::ip($ip);
+				if($ipInfo['country'] != $ipip['country_name']){
+					$ipInfo['country'] = $ipip['country_name'];
+					$ipInfo['province'] = $ipip['region_name'];
+					$ipInfo['city'] = $ipip['city_name'];
+				}
+			}
+		}
 
-        // 拒绝无IP请求
-        if (empty($ipInfo) || empty($ipInfo['country'])) {
-            return response()->view('auth.error', ['message' => trans('error.ForbiddenAccess')], 403);
-        }
+		// 拒绝无IP请求
+		if(empty($ipInfo) || empty($ipInfo['country'])){
+			return response()->view('auth.error', ['message' => trans('error.ForbiddenAccess')], 403);
+		}
 
-        if (!in_array($ipInfo['country'], ['本机地址', '局域网'])) {
-            // 拒绝大陆IP访问
-            if (Helpers::systemConfig()['is_forbid_china']) {
-                if (($ipInfo['country'] == '中国' && !in_array($ipInfo['province'], ['香港', '澳门', '台湾'])) || ($isIPv6 && $ipInfo['country'] == 'China')) {
-                    Log::info('识别到大陆IP,拒绝访问:' . $ip);
+		if(!in_array($ipInfo['country'], ['本机地址', '局域网'])){
+			// 拒绝大陆IP访问
+			if(Helpers::systemConfig()['is_forbid_china']){
+				if(($ipInfo['country'] == '中国' && !in_array($ipInfo['province'], ['香港', '澳门', '台湾'])) || ($isIPv6 && $ipInfo['country'] == 'China')){
+					Log::info('识别到大陆IP,拒绝访问:'.$ip);
 
-                    return response()->view('auth.error', ['message' => trans('error.ForbiddenChina')], 403);
-                }
-            }
+					return response()->view('auth.error', ['message' => trans('error.ForbiddenChina')], 403);
+				}
+			}
 
-            // 拒绝非大陆IP访问
-            if (Helpers::systemConfig()['is_forbid_oversea']) {
-                if ($ipInfo['country'] != '中国' || in_array($ipInfo['province'], ['香港', '澳门', '台湾']) || ($isIPv6 && $ipInfo['country'] != 'China')) {
-                    Log::info('识别到海外IP,拒绝访问:' . $ip . ' - ' . $ipInfo['country']);
+			// 拒绝非大陆IP访问
+			if(Helpers::systemConfig()['is_forbid_oversea']){
+				if($ipInfo['country'] != '中国' || in_array($ipInfo['province'], ['香港', '澳门', '台湾']) || ($isIPv6 && $ipInfo['country'] != 'China')){
+					Log::info('识别到海外IP,拒绝访问:'.$ip.' - '.$ipInfo['country']);
 
-                    return response()->view('auth.error', ['message' => trans('error.ForbiddenOversea')], 403);
-                }
-            }
-        }
+					return response()->view('auth.error', ['message' => trans('error.ForbiddenOversea')], 403);
+				}
+			}
+		}
 
-        return $next($request);
-    }
+		return $next($request);
+	}
 }

+ 16 - 15
app/Http/Middleware/isLogin.php

@@ -3,24 +3,25 @@
 namespace App\Http\Middleware;
 
 use Closure;
+use Illuminate\Http\Request;
 use Redirect;
 
 class isLogin
 {
-    /**
-     * 校验是否已登录
-     *
-     * @param  \Illuminate\Http\Request $request
-     * @param  \Closure                 $next
-     *
-     * @return mixed
-     */
-    public function handle($request, Closure $next)
-    {
-        if (auth()->guest()) {
-            return Redirect::to('login');
-        }
+	/**
+	 * 校验是否已登录
+	 *
+	 * @param Request $request
+	 * @param Closure                  $next
+	 *
+	 * @return mixed
+	 */
+	public function handle($request, Closure $next)
+	{
+		if(auth()->guest()){
+			return Redirect::to('login');
+		}
 
-        return $next($request);
-    }
+		return $next($request);
+	}
 }

+ 6 - 6
app/Http/Middleware/isSecurity.php

@@ -21,15 +21,15 @@ class isSecurity
 	{
 		$ip = getClientIP();
 		$code = $request->input('securityCode');
-		$cacheKey = 'SecurityLogin_' . ip2long($ip);
+		$cacheKey = 'SecurityLogin_'.ip2long($ip);
 		$websiteSecurityCode = Helpers::systemConfig()['website_security_code'];
 
-		if ($websiteSecurityCode && !Cache::has($cacheKey)) {
-			if ($code != $websiteSecurityCode) {
-				Log::info("拒绝非安全入口访问(" . $ip . ")");
+		if($websiteSecurityCode && !Cache::has($cacheKey)){
+			if($code != $websiteSecurityCode){
+				Log::info("拒绝非安全入口访问(".$ip.")");
 
-				return response()->view('auth.error', ['message' => trans('error.SecurityError') . ', ' . trans('error.Visit') . '<a href="/login?securityCode=" target="_self">' . trans('error.SecurityEnter') . '</a>']);
-			} else {
+				return response()->view('auth.error', ['message' => trans('error.SecurityError').', '.trans('error.Visit').'<a href="/login?securityCode=" target="_self">'.trans('error.SecurityEnter').'</a>']);
+			}else{
 				Cache::put($cacheKey, $ip, 120); // 缓存120分钟,因为每个session默认存活120分钟
 			}
 		}

+ 11 - 10
app/Http/Models/Article.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
@@ -10,19 +11,19 @@ use Illuminate\Database\Eloquent\SoftDeletes;
  * Class Article
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Article extends Model
 {
-    use SoftDeletes;
+	use SoftDeletes;
 
-    protected $table = 'article';
-    protected $primaryKey = 'id';
-    protected $dates = ['deleted_at'];
+	protected $table = 'article';
+	protected $primaryKey = 'id';
+	protected $dates = ['deleted_at'];
 
-    // 筛选类型
-    function scopeType($query, $type)
-    {
-        return $query->where('type', $type);
-    }
+	// 筛选类型
+	function scopeType($query, $type)
+	{
+		return $query->where('type', $type);
+	}
 }

+ 5 - 4
app/Http/Models/Config.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,12 +10,12 @@ use Illuminate\Database\Eloquent\Model;
  * Class Config
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Config extends Model
 {
-    protected $table = 'config';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'config';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 
 }

+ 5 - 4
app/Http/Models/Country.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,11 +10,11 @@ use Illuminate\Database\Eloquent\Model;
  * Class Country
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Country extends Model
 {
-    protected $table = 'country';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'country';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 }

+ 33 - 32
app/Http/Models/Coupon.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
@@ -10,39 +11,39 @@ use Illuminate\Database\Eloquent\SoftDeletes;
  * Class Goods
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Coupon extends Model
 {
-    use SoftDeletes;
-
-    protected $table = 'coupon';
-    protected $primaryKey = 'id';
-    protected $dates = ['deleted_at'];
-
-    // 筛选类型
-    function scopeType($query, $type)
-    {
-        return $query->where('type', $type);
-    }
-
-    function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setAmountAttribute($value)
-    {
-        $this->attributes['amount'] = $value * 100;
-    }
-
-    function getDiscountAttribute($value)
-    {
-        return $value * 10;
-    }
-
-    function setDiscountAttribute($value)
-    {
-        $this->attributes['discount'] = $value / 10;
-    }
+	use SoftDeletes;
+
+	protected $table = 'coupon';
+	protected $primaryKey = 'id';
+	protected $dates = ['deleted_at'];
+
+	// 筛选类型
+	function scopeType($query, $type)
+	{
+		return $query->where('type', $type);
+	}
+
+	function getAmountAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setAmountAttribute($value)
+	{
+		$this->attributes['amount'] = $value*100;
+	}
+
+	function getDiscountAttribute($value)
+	{
+		return $value*10;
+	}
+
+	function setDiscountAttribute($value)
+	{
+		$this->attributes['discount'] = $value/10;
+	}
 }

+ 4 - 3
app/Http/Models/CouponLog.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,11 +10,11 @@ use Illuminate\Database\Eloquent\Model;
  * Class Goods
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class CouponLog extends Model
 {
-    protected $table = 'coupon_log';
-    protected $primaryKey = 'id';
+	protected $table = 'coupon_log';
+	protected $primaryKey = 'id';
 
 }

+ 43 - 42
app/Http/Models/Device.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,53 +10,53 @@ use Illuminate\Database\Eloquent\Model;
  * Class Device
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Device extends Model
 {
-    protected $table = 'device';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'device';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 
-    function getTypeLabelAttribute()
-    {
-        switch ($this->attributes['type']) {
-            case 1:
-                $type_label = '<span class="label label-danger"> Shadowsocks(R) </span>';
-                break;
-            case 2:
-                $type_label = '<span class="label label-danger"> V2Ray </span>';
-                break;
-            default:
-                $type_label = '<span class="label label-default"> 其他 </span>';
-        }
+	function getTypeLabelAttribute()
+	{
+		switch($this->attributes['type']){
+			case 1:
+				$type_label = '<span class="label label-danger"> Shadowsocks(R) </span>';
+				break;
+			case 2:
+				$type_label = '<span class="label label-danger"> V2Ray </span>';
+				break;
+			default:
+				$type_label = '<span class="label label-default"> 其他 </span>';
+		}
 
-        return $type_label;
-    }
+		return $type_label;
+	}
 
-    function getPlatformLabelAttribute()
-    {
-        switch ($this->attributes['platform']) {
-            case 1:
-                $platform_label = '<i class="fa fa-apple"></i> iOS';
-                break;
-            case 2:
-                $platform_label = '<i class="fa fa-android"></i> Android';
-                break;
-            case 3:
-                $platform_label = '<i class="fa fa-apple"></i> Mac';
-                break;
-            case 4:
-                $platform_label = '<i class="fa fa-windows"></i> Windows';
-                break;
-            case 5:
-                $platform_label = '<i class="fa fa-linux"></i> Linux';
-                break;
-            case 0:
-            default:
-                $platform_label = '其他';
-        }
+	function getPlatformLabelAttribute()
+	{
+		switch($this->attributes['platform']){
+			case 1:
+				$platform_label = '<i class="fa fa-apple"></i> iOS';
+				break;
+			case 2:
+				$platform_label = '<i class="fa fa-android"></i> Android';
+				break;
+			case 3:
+				$platform_label = '<i class="fa fa-apple"></i> Mac';
+				break;
+			case 4:
+				$platform_label = '<i class="fa fa-windows"></i> Windows';
+				break;
+			case 5:
+				$platform_label = '<i class="fa fa-linux"></i> Linux';
+				break;
+			case 0:
+			default:
+				$platform_label = '其他';
+		}
 
-        return $platform_label;
-    }
+		return $platform_label;
+	}
 }

+ 4 - 3
app/Http/Models/EmailLog.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,11 +10,11 @@ use Illuminate\Database\Eloquent\Model;
  * Class EmailLog
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class EmailLog extends Model
 {
-    protected $table = 'email_log';
-    protected $primaryKey = 'id';
+	protected $table = 'email_log';
+	protected $primaryKey = 'id';
 
 }

+ 33 - 32
app/Http/Models/Goods.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
@@ -10,39 +11,39 @@ use Illuminate\Database\Eloquent\SoftDeletes;
  * Class Goods
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Goods extends Model
 {
-    use SoftDeletes;
-    protected $table = 'goods';
-    protected $primaryKey = 'id';
-    protected $dates = ['deleted_at'];
-
-    function scopeType($query, $type)
-    {
-        return $query->where('type', $type)->where('status', 1)->orderBy('sort', 'desc');
-    }
-
-    function label()
-    {
-        return $this->hasMany(GoodsLabel::class, 'goods_id', 'id');
-    }
-
-    function getPriceAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setPriceAttribute($value)
-    {
-        $this->attributes['price'] = $value * 100;
-    }
-
-    function getTrafficLabelAttribute()
-    {
-        $traffic_label = flowAutoShow($this->attributes['traffic'] * 1048576);
-
-        return $traffic_label;
-    }
+	use SoftDeletes;
+	protected $table = 'goods';
+	protected $primaryKey = 'id';
+	protected $dates = ['deleted_at'];
+
+	function scopeType($query, $type)
+	{
+		return $query->where('type', $type)->where('status', 1)->orderBy('sort', 'desc');
+	}
+
+	function label()
+	{
+		return $this->hasMany(GoodsLabel::class, 'goods_id', 'id');
+	}
+
+	function getPriceAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setPriceAttribute($value)
+	{
+		$this->attributes['price'] = $value*100;
+	}
+
+	function getTrafficLabelAttribute()
+	{
+		$traffic_label = flowAutoShow($this->attributes['traffic']*1048576);
+
+		return $traffic_label;
+	}
 }

+ 9 - 8
app/Http/Models/GoodsLabel.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,16 +10,16 @@ use Illuminate\Database\Eloquent\Model;
  * Class GoodsLabel
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class GoodsLabel extends Model
 {
-    protected $table = 'goods_label';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'goods_label';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 
-    function goods()
-    {
-        return $this->hasOne(Goods::class, 'id', 'goods_id');
-    }
+	function goods()
+	{
+		return $this->hasOne(Goods::class, 'id', 'goods_id');
+	}
 }

+ 22 - 21
app/Http/Models/Invite.php

@@ -3,6 +3,7 @@
 namespace App\Http\Models;
 
 use Auth;
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 use Illuminate\Database\Eloquent\SoftDeletes;
 
@@ -11,29 +12,29 @@ use Illuminate\Database\Eloquent\SoftDeletes;
  * Class Invite
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Invite extends Model
 {
-    use SoftDeletes;
-
-    protected $table = 'invite';
-    protected $primaryKey = 'id';
-    protected $dates = ['deleted_at'];
-
-    function scopeUid($query)
-    {
-        return $query->where('uid', Auth::user()->id);
-    }
-
-    function generator()
-    {
-        return $this->hasOne(User::class, 'id', 'uid');
-    }
-
-    function user()
-    {
-        return $this->hasOne(User::class, 'id', 'fuid');
-    }
+	use SoftDeletes;
+
+	protected $table = 'invite';
+	protected $primaryKey = 'id';
+	protected $dates = ['deleted_at'];
+
+	function scopeUid($query)
+	{
+		return $query->where('uid', Auth::user()->id);
+	}
+
+	function generator()
+	{
+		return $this->hasOne(User::class, 'id', 'uid');
+	}
+
+	function user()
+	{
+		return $this->hasOne(User::class, 'id', 'fuid');
+	}
 
 }

+ 5 - 4
app/Http/Models/Label.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,11 +10,11 @@ use Illuminate\Database\Eloquent\Model;
  * Class Label
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Label extends Model
 {
-    protected $table = 'label';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'label';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 }

+ 5 - 4
app/Http/Models/Level.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,11 +10,11 @@ use Illuminate\Database\Eloquent\Model;
  * Class Level
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Level extends Model
 {
-    protected $table = 'level';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'level';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 }

+ 21 - 20
app/Http/Models/Marketing.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,29 +10,29 @@ use Illuminate\Database\Eloquent\Model;
  * Class Marketing
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Marketing extends Model
 {
-    protected $table = 'marketing';
-    protected $primaryKey = 'id';
-    protected $appends = ['status_label'];
+	protected $table = 'marketing';
+	protected $primaryKey = 'id';
+	protected $appends = ['status_label'];
 
-    function getStatusLabelAttribute()
-    {
-        $status_label = '';
-        switch ($this->attributes['status']) {
-            case -1:
-                $status_label = '失败';
-                break;
-            case 0:
-                $status_label = '待推送';
-                break;
-            case 1:
-                $status_label = '成功';
-                break;
-        }
+	function getStatusLabelAttribute()
+	{
+		$status_label = '';
+		switch($this->attributes['status']){
+			case -1:
+				$status_label = '失败';
+				break;
+			case 0:
+				$status_label = '待推送';
+				break;
+			case 1:
+				$status_label = '成功';
+				break;
+		}
 
-        return $status_label;
-    }
+		return $status_label;
+	}
 }

+ 59 - 58
app/Http/Models/Order.php

@@ -3,6 +3,7 @@
 namespace App\Http\Models;
 
 use Auth;
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -10,76 +11,76 @@ use Illuminate\Database\Eloquent\Model;
  * Class Order
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Order extends Model
 {
-    protected $table = 'order';
-    protected $primaryKey = 'oid';
-    protected $appends = ['status_label'];
+	protected $table = 'order';
+	protected $primaryKey = 'oid';
+	protected $appends = ['status_label'];
 
-    function scopeUid($query)
-    {
-        return $query->where('user_id', Auth::user()->id);
-    }
+	function scopeUid($query)
+	{
+		return $query->where('user_id', Auth::user()->id);
+	}
 
-    function user()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
+	function user()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
 
-    function goods()
-    {
-        return $this->hasOne(Goods::class, 'id', 'goods_id')->withTrashed();
-    }
+	function goods()
+	{
+		return $this->hasOne(Goods::class, 'id', 'goods_id')->withTrashed();
+	}
 
-    function coupon()
-    {
-        return $this->hasOne(Coupon::class, 'id', 'coupon_id')->withTrashed();
-    }
+	function coupon()
+	{
+		return $this->hasOne(Coupon::class, 'id', 'coupon_id')->withTrashed();
+	}
 
-    function payment()
-    {
-        return $this->hasOne(Payment::class, 'oid', 'oid');
-    }
+	function payment()
+	{
+		return $this->hasOne(Payment::class, 'oid', 'oid');
+	}
 
-    function getOriginAmountAttribute($value)
-    {
-        return $value / 100;
-    }
+	function getOriginAmountAttribute($value)
+	{
+		return $value/100;
+	}
 
-    function setOriginAmountAttribute($value)
-    {
-        return $this->attributes['origin_amount'] = $value * 100;
-    }
+	function setOriginAmountAttribute($value)
+	{
+		return $this->attributes['origin_amount'] = $value*100;
+	}
 
-    function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
+	function getAmountAttribute($value)
+	{
+		return $value/100;
+	}
 
-    function setAmountAttribute($value)
-    {
-        return $this->attributes['amount'] = $value * 100;
-    }
+	function setAmountAttribute($value)
+	{
+		return $this->attributes['amount'] = $value*100;
+	}
 
-    function getStatusLabelAttribute()
-    {
-        switch ($this->attributes['status']) {
-            case -1:
-                $status_label = '已关闭';
-                break;
-            case 1:
-                $status_label = '已支付待确认';
-                break;
-            case 2:
-                $status_label = '已完成';
-                break;
-            case 0:
-            default:
-                $status_label = '待支付';
-        }
+	function getStatusLabelAttribute()
+	{
+		switch($this->attributes['status']){
+			case -1:
+				$status_label = '已关闭';
+				break;
+			case 1:
+				$status_label = '已支付待确认';
+				break;
+			case 2:
+				$status_label = '已完成';
+				break;
+			case 0:
+			default:
+				$status_label = '待支付';
+		}
 
-        return $status_label;
-    }
+		return $status_label;
+	}
 }

+ 34 - 33
app/Http/Models/OrderGoods.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,40 +10,40 @@ use Illuminate\Database\Eloquent\Model;
  * Class OrderGoods
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class OrderGoods extends Model
 {
-    protected $table = 'order_goods';
-    protected $primaryKey = 'id';
-
-    function user()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
-
-    function goods()
-    {
-        return $this->hasOne(Goods::class, 'id', 'goods_id');
-    }
-
-    function getOriginPriceAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setOriginPriceAttribute($value)
-    {
-        return $this->attributes['origin_price'] = $value * 100;
-    }
-
-    function getPriceAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setPriceAttribute($value)
-    {
-        return $this->attributes['price'] = $value * 100;
-    }
+	protected $table = 'order_goods';
+	protected $primaryKey = 'id';
+
+	function user()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
+
+	function goods()
+	{
+		return $this->hasOne(Goods::class, 'id', 'goods_id');
+	}
+
+	function getOriginPriceAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setOriginPriceAttribute($value)
+	{
+		return $this->attributes['origin_price'] = $value*100;
+	}
+
+	function getPriceAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setPriceAttribute($value)
+	{
+		return $this->attributes['price'] = $value*100;
+	}
 }

+ 54 - 53
app/Http/Models/Payment.php

@@ -3,6 +3,7 @@
 namespace App\Http\Models;
 
 use Auth;
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -10,69 +11,69 @@ use Illuminate\Database\Eloquent\Model;
  * Class Payment
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Payment extends Model
 {
-    protected $table = 'payment';
-    protected $primaryKey = 'id';
-    protected $appends = ['status_label'];
+	protected $table = 'payment';
+	protected $primaryKey = 'id';
+	protected $appends = ['status_label'];
 
-    function scopeUid($query)
-    {
-        return $query->where('user_id', Auth::user()->id);
-    }
+	function scopeUid($query)
+	{
+		return $query->where('user_id', Auth::user()->id);
+	}
 
-    function user()
-    {
-        return $this->belongsTo(User::class, 'user_id', 'id');
-    }
+	function user()
+	{
+		return $this->belongsTo(User::class, 'user_id', 'id');
+	}
 
-    function order()
-    {
-        return $this->belongsTo(Order::class, 'oid', 'oid');
-    }
+	function order()
+	{
+		return $this->belongsTo(Order::class, 'oid', 'oid');
+	}
 
-    function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
+	function getAmountAttribute($value)
+	{
+		return $value/100;
+	}
 
-    function setAmountAttribute($value)
-    {
-        return $this->attributes['amount'] = $value * 100;
-    }
+	function setAmountAttribute($value)
+	{
+		return $this->attributes['amount'] = $value*100;
+	}
 
-    // 订单状态
-    function getStatusLabelAttribute()
-    {
-        switch ($this->attributes['status']) {
-            case -1:
-                $status_label = '支付失败';
-                break;
-            case 1:
-                $status_label = '支付成功';
-                break;
-            case 0:
-            default:
-                $status_label = '等待支付';
-        }
+	// 订单状态
+	function getStatusLabelAttribute()
+	{
+		switch($this->attributes['status']){
+			case -1:
+				$status_label = '支付失败';
+				break;
+			case 1:
+				$status_label = '支付成功';
+				break;
+			case 0:
+			default:
+				$status_label = '等待支付';
+		}
 
-        return $status_label;
-    }
+		return $status_label;
+	}
 
-    // 支付方式
-    function getPayWayLabelAttribute()
-    {
-        switch ($this->attributes['pay_way']) {
-            case 1:
-                $pay_way_label = '微信';
-                break;
-            case 2:
-            default:
-                $pay_way_label = '支付宝';
-        }
+	// 支付方式
+	function getPayWayLabelAttribute()
+	{
+		switch($this->attributes['pay_way']){
+			case 1:
+				$pay_way_label = '微信';
+				break;
+			case 2:
+			default:
+				$pay_way_label = '支付宝';
+		}
 
-        return $pay_way_label;
-    }
+		return $pay_way_label;
+	}
 }

+ 24 - 23
app/Http/Models/PaymentCallback.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,32 +10,32 @@ use Illuminate\Database\Eloquent\Model;
  * Class PaymentCallback
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class PaymentCallback extends Model
 {
-    protected $table = 'payment_callback';
-    protected $primaryKey = 'id';
-    protected $appends = ['status_label'];
+	protected $table = 'payment_callback';
+	protected $primaryKey = 'id';
+	protected $appends = ['status_label'];
 
-    function getStatusLabelAttribute()
-    {
-        $status_label = '';
-        switch ($this->attributes['status']) {
-            case 'WAIT_BUYER_PAY':
-                $status_label = '等待买家付款';
-                break;
-            case 'WAIT_SELLER_SEND_GOODS':
-                $status_label = '等待卖家发货';
-                break;
-            case 'TRADE_SUCCESS':
-                $status_label = '交易成功';
-                break;
-            case 'PAID':
-                $status_label = '支付完成';
-                break;
-        }
+	function getStatusLabelAttribute()
+	{
+		$status_label = '';
+		switch($this->attributes['status']){
+			case 'WAIT_BUYER_PAY':
+				$status_label = '等待买家付款';
+				break;
+			case 'WAIT_SELLER_SEND_GOODS':
+				$status_label = '等待卖家发货';
+				break;
+			case 'TRADE_SUCCESS':
+				$status_label = '交易成功';
+				break;
+			case 'PAID':
+				$status_label = '支付完成';
+				break;
+		}
 
-        return $status_label;
-    }
+		return $status_label;
+	}
 }

+ 44 - 43
app/Http/Models/ReferralApply.php

@@ -3,6 +3,7 @@
 namespace App\Http\Models;
 
 use Auth;
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -10,50 +11,50 @@ use Illuminate\Database\Eloquent\Model;
  * Class ReferralApply
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class ReferralApply extends Model
 {
-    protected $table = 'referral_apply';
-    protected $primaryKey = 'id';
-
-    function scopeUid($query)
-    {
-        return $query->where('user_id', Auth::user()->id);
-    }
-
-    function User()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
-
-    function getBeforeAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setBeforeAttribute($value)
-    {
-        $this->attributes['before'] = $value * 100;
-    }
-
-    function getAfterAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setAfterAttribute($value)
-    {
-        $this->attributes['after'] = $value * 100;
-    }
-
-    function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setAmountAttribute($value)
-    {
-        $this->attributes['amount'] = $value * 100;
-    }
+	protected $table = 'referral_apply';
+	protected $primaryKey = 'id';
+
+	function scopeUid($query)
+	{
+		return $query->where('user_id', Auth::user()->id);
+	}
+
+	function User()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
+
+	function getBeforeAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setBeforeAttribute($value)
+	{
+		$this->attributes['before'] = $value*100;
+	}
+
+	function getAfterAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setAfterAttribute($value)
+	{
+		$this->attributes['after'] = $value*100;
+	}
+
+	function getAmountAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setAmountAttribute($value)
+	{
+		$this->attributes['amount'] = $value*100;
+	}
 }

+ 44 - 43
app/Http/Models/ReferralLog.php

@@ -3,6 +3,7 @@
 namespace App\Http\Models;
 
 use Auth;
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -10,50 +11,50 @@ use Illuminate\Database\Eloquent\Model;
  * Class ReferralLog
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class ReferralLog extends Model
 {
-    protected $table = 'referral_log';
-    protected $primaryKey = 'id';
-
-    function scopeUid($query)
-    {
-        return $query->where('ref_user_id', Auth::user()->id);
-    }
-
-    function user()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
-
-    function ref_user()
-    {
-        return $this->hasOne(User::class, 'id', 'ref_user_id');
-    }
-
-    function order()
-    {
-        return $this->hasOne(Order::class, 'oid', 'order_id');
-    }
-
-    function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setAmountAttribute($value)
-    {
-        $this->attributes['amount'] = $value * 100;
-    }
-
-    function getRefAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setRefAmountAttribute($value)
-    {
-        $this->attributes['ref_amount'] = $value * 100;
-    }
+	protected $table = 'referral_log';
+	protected $primaryKey = 'id';
+
+	function scopeUid($query)
+	{
+		return $query->where('ref_user_id', Auth::user()->id);
+	}
+
+	function user()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
+
+	function ref_user()
+	{
+		return $this->hasOne(User::class, 'id', 'ref_user_id');
+	}
+
+	function order()
+	{
+		return $this->hasOne(Order::class, 'oid', 'order_id');
+	}
+
+	function getAmountAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setAmountAttribute($value)
+	{
+		$this->attributes['amount'] = $value*100;
+	}
+
+	function getRefAmountAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setRefAmountAttribute($value)
+	{
+		$this->attributes['ref_amount'] = $value*100;
+	}
 }

+ 5 - 4
app/Http/Models/SensitiveWords.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,11 +10,11 @@ use Illuminate\Database\Eloquent\Model;
  * Class SensitiveWords
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class SensitiveWords extends Model
 {
-    protected $table = 'sensitive_words';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'sensitive_words';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 }

+ 15 - 14
app/Http/Models/SsConfig.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,23 +10,23 @@ use Illuminate\Database\Eloquent\Model;
  * Class SsConfig
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class SsConfig extends Model
 {
-    protected $table = 'ss_config';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'ss_config';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 
-    // 筛选默认
-    function scopeDefault($query)
-    {
-        $query->where('is_default', 1);
-    }
+	// 筛选默认
+	function scopeDefault($query)
+	{
+		$query->where('is_default', 1);
+	}
 
-    // 筛选类型
-    function scopeType($query, $type)
-    {
-        $query->where('type', $type);
-    }
+	// 筛选类型
+	function scopeType($query, $type)
+	{
+		$query->where('type', $type);
+	}
 }

+ 4 - 3
app/Http/Models/SsGroup.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,11 +10,11 @@ use Illuminate\Database\Eloquent\Model;
  * Class SsNodeGroup
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class SsGroup extends Model
 {
-    protected $table = 'ss_group';
-    protected $primaryKey = 'id';
+	protected $table = 'ss_group';
+	protected $primaryKey = 'id';
 
 }

+ 5 - 4
app/Http/Models/SsGroupNode.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,12 +10,12 @@ use Illuminate\Database\Eloquent\Model;
  * Class SsNodeGroup
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class SsGroupNode extends Model
 {
-    protected $table = 'ss_group_node';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'ss_group_node';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 
 }

+ 8 - 7
app/Http/Models/SsNode.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,15 +10,15 @@ use Illuminate\Database\Eloquent\Model;
  * Class SsNode
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class SsNode extends Model
 {
-    protected $table = 'ss_node';
-    protected $primaryKey = 'id';
+	protected $table = 'ss_node';
+	protected $primaryKey = 'id';
 
-    function label()
-    {
-        return $this->hasMany(SsNodeLabel::class, 'node_id', 'id');
-    }
+	function label()
+	{
+		return $this->hasMany(SsNodeLabel::class, 'node_id', 'id');
+	}
 }

+ 5 - 4
app/Http/Models/SsNodeInfo.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,12 +10,12 @@ use Illuminate\Database\Eloquent\Model;
  * Class SsNodeInfo
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class SsNodeInfo extends Model
 {
-    protected $table = 'ss_node_info';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'ss_node_info';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 
 }

+ 12 - 11
app/Http/Models/SsNodeIp.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,20 +10,20 @@ use Illuminate\Database\Eloquent\Model;
  * Class SsNodeIp
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class SsNodeIp extends Model
 {
-    protected $table = 'ss_node_ip';
-    protected $primaryKey = 'id';
+	protected $table = 'ss_node_ip';
+	protected $primaryKey = 'id';
 
-    function node()
-    {
-        return $this->belongsTo(SsNode::class, 'node_id', 'id');
-    }
+	function node()
+	{
+		return $this->belongsTo(SsNode::class, 'node_id', 'id');
+	}
 
-    function user()
-    {
-        return $this->belongsTo(User::class, 'port', 'port');
-    }
+	function user()
+	{
+		return $this->belongsTo(User::class, 'port', 'port');
+	}
 }

+ 10 - 9
app/Http/Models/SsNodeLabel.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,17 +10,17 @@ use Illuminate\Database\Eloquent\Model;
  * Class SsNodeLabel
  *
  * @package App\Http\Models
- * @property-read \App\Http\Models\Label $labelInfo
- * @mixin \Eloquent
+ * @property-read Label $labelInfo
+ * @mixin Eloquent
  */
 class SsNodeLabel extends Model
 {
-    protected $table = 'ss_node_label';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'ss_node_label';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 
-    function labelInfo()
-    {
-        return $this->hasOne(Label::class, 'id', 'label_id');
-    }
+	function labelInfo()
+	{
+		return $this->hasOne(Label::class, 'id', 'label_id');
+	}
 }

+ 5 - 4
app/Http/Models/SsNodeOnlineLog.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,12 +10,12 @@ use Illuminate\Database\Eloquent\Model;
  * Class SsNodeOnlineLog
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class SsNodeOnlineLog extends Model
 {
-    protected $table = 'ss_node_online_log';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'ss_node_online_log';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 
 }

+ 8 - 7
app/Http/Models/SsNodeTrafficDaily.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,16 +10,16 @@ use Illuminate\Database\Eloquent\Model;
  * Class SsUserTrafficDaily
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class SsNodeTrafficDaily extends Model
 {
-    protected $table = 'ss_node_traffic_daily';
-    protected $primaryKey = 'id';
+	protected $table = 'ss_node_traffic_daily';
+	protected $primaryKey = 'id';
 
-    function info()
-    {
-        return $this->hasOne(SsNode::class, 'id', 'node_id');
-    }
+	function info()
+	{
+		return $this->hasOne(SsNode::class, 'id', 'node_id');
+	}
 
 }

+ 8 - 7
app/Http/Models/SsNodeTrafficHourly.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,15 +10,15 @@ use Illuminate\Database\Eloquent\Model;
  * Class SsUserTrafficHourly
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class SsNodeTrafficHourly extends Model
 {
-    protected $table = 'ss_node_traffic_hourly';
-    protected $primaryKey = 'id';
+	protected $table = 'ss_node_traffic_hourly';
+	protected $primaryKey = 'id';
 
-    function info()
-    {
-        return $this->hasOne(SsNode::class, 'id', 'node_id');
-    }
+	function info()
+	{
+		return $this->hasOne(SsNode::class, 'id', 'node_id');
+	}
 }

+ 12 - 11
app/Http/Models/Ticket.php

@@ -3,6 +3,7 @@
 namespace App\Http\Models;
 
 use Auth;
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -10,20 +11,20 @@ use Illuminate\Database\Eloquent\Model;
  * Class Ticket
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class Ticket extends Model
 {
-    protected $table = 'ticket';
-    protected $primaryKey = 'id';
+	protected $table = 'ticket';
+	protected $primaryKey = 'id';
 
-    function scopeUid($query)
-    {
-        return $query->where('user_id', Auth::user()->id);
-    }
+	function scopeUid($query)
+	{
+		return $query->where('user_id', Auth::user()->id);
+	}
 
-    function user()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
+	function user()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
 }

+ 8 - 7
app/Http/Models/TicketReply.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,15 +10,15 @@ use Illuminate\Database\Eloquent\Model;
  * Class TicketReply
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class TicketReply extends Model
 {
-    protected $table = 'ticket_reply';
-    protected $primaryKey = 'id';
+	protected $table = 'ticket_reply';
+	protected $primaryKey = 'id';
 
-    function user()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
+	function user()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
 }

+ 46 - 45
app/Http/Models/User.php

@@ -3,59 +3,60 @@
 namespace App\Http\Models;
 
 use Auth;
-use Illuminate\Notifications\Notifiable;
+use Eloquent;
 use Illuminate\Foundation\Auth\User as Authenticatable;
+use Illuminate\Notifications\Notifiable;
 
 /**
  * 用户信息
  * Class User
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class User extends Authenticatable
 {
-    use Notifiable;
-    protected $table = 'user';
-    protected $primaryKey = 'id';
-
-    function scopeUid($query)
-    {
-        return $query->where('id', Auth::user()->id);
-    }
-
-    function levelList()
-    {
-        return $this->hasOne(Level::class, 'level', 'level');
-    }
-
-    function payment()
-    {
-        return $this->hasMany(Payment::class, 'user_id', 'id');
-    }
-
-    function label()
-    {
-        return $this->hasMany(UserLabel::class, 'user_id', 'id');
-    }
-
-    function subscribe()
-    {
-        return $this->hasOne(UserSubscribe::class, 'user_id', 'id');
-    }
-
-    function referral()
-    {
-        return $this->hasOne(User::class, 'id', 'referral_uid');
-    }
-
-    function getBalanceAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setBalanceAttribute($value)
-    {
-        return $this->attributes['balance'] = $value * 100;
-    }
+	use Notifiable;
+	protected $table = 'user';
+	protected $primaryKey = 'id';
+
+	function scopeUid($query)
+	{
+		return $query->where('id', Auth::user()->id);
+	}
+
+	function levelList()
+	{
+		return $this->hasOne(Level::class, 'level', 'level');
+	}
+
+	function payment()
+	{
+		return $this->hasMany(Payment::class, 'user_id', 'id');
+	}
+
+	function label()
+	{
+		return $this->hasMany(UserLabel::class, 'user_id', 'id');
+	}
+
+	function subscribe()
+	{
+		return $this->hasOne(UserSubscribe::class, 'user_id', 'id');
+	}
+
+	function referral()
+	{
+		return $this->hasOne(User::class, 'id', 'referral_uid');
+	}
+
+	function getBalanceAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setBalanceAttribute($value)
+	{
+		return $this->attributes['balance'] = $value*100;
+	}
 }

+ 40 - 39
app/Http/Models/UserBalanceLog.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,46 +10,46 @@ use Illuminate\Database\Eloquent\Model;
  * Class UserBalanceLog
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class UserBalanceLog extends Model
 {
-    protected $table = 'user_balance_log';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
-
-    function user()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
-
-    function getBeforeAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setBeforeAttribute($value)
-    {
-        return $this->attributes['before'] = $value * 100;
-    }
-
-    function getAfterAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setAfterAttribute($value)
-    {
-        return $this->attributes['after'] = $value * 100;
-    }
-
-    function getAmountAttribute($value)
-    {
-        return $value / 100;
-    }
-
-    function setAmountAttribute($value)
-    {
-        return $this->attributes['amount'] = $value * 100;
-    }
+	protected $table = 'user_balance_log';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
+
+	function user()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
+
+	function getBeforeAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setBeforeAttribute($value)
+	{
+		return $this->attributes['before'] = $value*100;
+	}
+
+	function getAfterAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setAfterAttribute($value)
+	{
+		return $this->attributes['after'] = $value*100;
+	}
+
+	function getAmountAttribute($value)
+	{
+		return $value/100;
+	}
+
+	function setAmountAttribute($value)
+	{
+		return $this->attributes['amount'] = $value*100;
+	}
 }

+ 8 - 7
app/Http/Models/UserBanLog.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,15 +10,15 @@ use Illuminate\Database\Eloquent\Model;
  * Class UserBanLog
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class UserBanLog extends Model
 {
-    protected $table = 'user_ban_log';
-    protected $primaryKey = 'id';
+	protected $table = 'user_ban_log';
+	protected $primaryKey = 'id';
 
-    function user()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
+	function user()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
 }

+ 13 - 12
app/Http/Models/UserLabel.php

@@ -3,6 +3,7 @@
 namespace App\Http\Models;
 
 use Auth;
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -10,21 +11,21 @@ use Illuminate\Database\Eloquent\Model;
  * Class UserLabel
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class UserLabel extends Model
 {
-    protected $table = 'user_label';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'user_label';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 
-    function scopeUid($query)
-    {
-        return $query->where('user_id', Auth::user()->id);
-    }
+	function scopeUid($query)
+	{
+		return $query->where('user_id', Auth::user()->id);
+	}
 
-    function user()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
+	function user()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
 }

+ 8 - 7
app/Http/Models/UserLoginLog.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,15 +10,15 @@ use Illuminate\Database\Eloquent\Model;
  * Class UserLoginLog
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class UserLoginLog extends Model
 {
-    protected $table = 'user_login_log';
-    protected $primaryKey = 'id';
+	protected $table = 'user_login_log';
+	protected $primaryKey = 'id';
 
-    function user()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
+	function user()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
 }

+ 12 - 11
app/Http/Models/UserSubscribe.php

@@ -3,6 +3,7 @@
 namespace App\Http\Models;
 
 use Auth;
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -10,20 +11,20 @@ use Illuminate\Database\Eloquent\Model;
  * Class UserSubscribe
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class UserSubscribe extends Model
 {
-    protected $table = 'user_subscribe';
-    protected $primaryKey = 'id';
+	protected $table = 'user_subscribe';
+	protected $primaryKey = 'id';
 
-    function scopeUid($query)
-    {
-        return $query->where('user_id', Auth::user()->id);
-    }
+	function scopeUid($query)
+	{
+		return $query->where('user_id', Auth::user()->id);
+	}
 
-    function User()
-    {
-        return $this->hasOne(User::class, 'id', 'user_id');
-    }
+	function User()
+	{
+		return $this->hasOne(User::class, 'id', 'user_id');
+	}
 }

+ 5 - 4
app/Http/Models/UserSubscribeLog.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,12 +10,12 @@ use Illuminate\Database\Eloquent\Model;
  * Class UserSubscribeLog
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class UserSubscribeLog extends Model
 {
-    protected $table = 'user_subscribe_log';
-    protected $primaryKey = 'id';
-    public $timestamps = false;
+	protected $table = 'user_subscribe_log';
+	protected $primaryKey = 'id';
+	public $timestamps = FALSE;
 
 }

+ 8 - 7
app/Http/Models/UserTrafficDaily.php

@@ -2,6 +2,7 @@
 
 namespace App\Http\Models;
 
+use Eloquent;
 use Illuminate\Database\Eloquent\Model;
 
 /**
@@ -9,15 +10,15 @@ use Illuminate\Database\Eloquent\Model;
  * Class UserTrafficDaily
  *
  * @package App\Http\Models
- * @mixin \Eloquent
+ * @mixin Eloquent
  */
 class UserTrafficDaily extends Model
 {
-    protected $table = 'user_traffic_daily';
-    protected $primaryKey = 'id';
+	protected $table = 'user_traffic_daily';
+	protected $primaryKey = 'id';
 
-    function node()
-    {
-        return $this->hasOne(SsNode::class, 'id', 'node_id');
-    }
+	function node()
+	{
+		return $this->hasOne(SsNode::class, 'id', 'node_id');
+	}
 }

Algunos archivos no se mostraron porque demasiados archivos cambiaron en este cambio