wesmiler il y a 1 an
Parent
commit
e21e2f4d39
40 fichiers modifiés avec 3258 ajouts et 263 suppressions
  1. BIN
      addons/mpapp2/static/icons/heart-active.png
  2. BIN
      addons/mpapp2/static/icons/heart.png
  3. BIN
      addons/mpapp2/static/icons/home-active.png
  4. BIN
      addons/mpapp2/static/icons/home.png
  5. BIN
      addons/mpapp2/static/icons/mime-active.png
  6. BIN
      addons/mpapp2/static/icons/mine.png
  7. BIN
      addons/mpapp2/static/icons/shop-active.png
  8. BIN
      addons/mpapp2/static/icons/shop.png
  9. BIN
      addons/mpapp2/static/icons/star-active.png
  10. BIN
      addons/mpapp2/static/icons/star.png
  11. 197 98
      app/Helpers/common.php
  12. 133 26
      app/Http/Controllers/Api/LoginController.php
  13. 96 0
      app/Http/Controllers/Api/v1/IndexController.php
  14. 113 0
      app/Http/Controllers/Api/v1/MemberController.php
  15. 2 1
      app/Http/Controllers/Api/webApp.php
  16. 4 4
      app/Http/Middleware/WebLogin.php
  17. 3 1
      app/Http/Validator/MemberValidator.php
  18. 24 0
      app/Models/AdCallbackModel.php
  19. 24 0
      app/Models/AdConfigModel.php
  20. 24 0
      app/Models/AdRecordModel.php
  21. 35 0
      app/Models/DossierModel.php
  22. 24 0
      app/Models/DossierTypeModel.php
  23. 24 0
      app/Models/GoodsCategoryModel.php
  24. 35 0
      app/Models/GoodsModel.php
  25. 24 0
      app/Models/GoodsSkuModel.php
  26. 32 12
      app/Models/MemberModel.php
  27. 24 0
      app/Models/OrderGoodsModel.php
  28. 24 0
      app/Models/OrderModel.php
  29. 974 0
      app/Services/Api/GoodsService.php
  30. 497 0
      app/Services/Api/MemberService.php
  31. 39 0
      app/Services/Common/CityService.php
  32. 5 0
      app/Services/Common/ConfigGroupService.php
  33. 395 0
      app/Services/EmailService.php
  34. 154 0
      app/Services/SmsService.php
  35. 175 0
      app/Services/SupplyService.php
  36. 72 0
      app/Services/ToolService.php
  37. 59 119
      config/mail.php
  38. 7 0
      config/params.php
  39. 7 2
      resources/lang/zh-cn/api.php
  40. 32 0
      resources/views/emails/index.blade.php

BIN
addons/mpapp2/static/icons/heart-active.png


BIN
addons/mpapp2/static/icons/heart.png


BIN
addons/mpapp2/static/icons/home-active.png


BIN
addons/mpapp2/static/icons/home.png


BIN
addons/mpapp2/static/icons/mime-active.png


BIN
addons/mpapp2/static/icons/mine.png


BIN
addons/mpapp2/static/icons/shop-active.png


BIN
addons/mpapp2/static/icons/shop.png


BIN
addons/mpapp2/static/icons/star-active.png


BIN
addons/mpapp2/static/icons/star.png


+ 197 - 98
app/Helpers/common.php

@@ -90,7 +90,7 @@ if (!function_exists('array2xml')) {
      */
     function array2xml($arr, $ignore = true, $level = 1)
     {
-        $s     = $level == 1 ? "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n<root>\r\n" : '';
+        $s = $level == 1 ? "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\r\n<root>\r\n" : '';
         $space = str_repeat("\t", $level);
         foreach ($arr as $k => $v) {
             if (!is_array($v)) {
@@ -118,7 +118,7 @@ if (!function_exists('array_merge_multiple')) {
     function array_merge_multiple($array1, $array2)
     {
         $merge = $array1 + $array2;
-        $data  = [];
+        $data = [];
         foreach ($merge as $key => $val) {
             if (isset($array1[$key])
                 && is_array($array1[$key])
@@ -315,7 +315,7 @@ if (!function_exists('datetime')) {
      */
     function datetime($time, $format = 'Y-m-d H:i:s')
     {
-        if($time == '0000-00-00 00:00:00'){
+        if ($time == '0000-00-00 00:00:00') {
             return '';
         }
         $time = is_numeric($time) ? $time : strtotime($time);
@@ -332,10 +332,10 @@ if (!function_exists('dateForWeek')) {
      */
     function dateForWeek($time)
     {
-        if(empty($time)){
+        if (empty($time)) {
             return false;
         }
-        $time = !is_int($time)? strtotime($time) : $time;
+        $time = !is_int($time) ? strtotime($time) : $time;
         $weeks = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
         $week = date("w", $time);
         $cweek = date("w");
@@ -353,12 +353,12 @@ if (!function_exists('dateFormat')) {
      * @param $time 时间戳
      * @return false|string
      */
-    function dateFormat($time, $format='m月d日')
+    function dateFormat($time, $format = 'm月d日')
     {
-        if(empty($time)){
+        if (empty($time)) {
             return false;
         }
-        $time = !is_int($time)? strtotime($time) : $time;
+        $time = !is_int($time) ? strtotime($time) : $time;
         $weeks = ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"];
         $week = date("w", $time);
         $cweek = date("w");
@@ -610,11 +610,11 @@ if (!function_exists('format_bank_card')) {
      * @author laravel开发员
      * @date 2019/5/23
      */
-    function format_bank_card($card_no, $is_format = true, $hidden=true)
+    function format_bank_card($card_no, $is_format = true, $hidden = true)
     {
-        if($hidden){
-            $format_card_no = '****'.substr($card_no, -4, 4);
-        }else if ($is_format) {
+        if ($hidden) {
+            $format_card_no = '****' . substr($card_no, -4, 4);
+        } else if ($is_format) {
             // 截取银行卡号前4位
             $prefix = substr($card_no, 0, 4);
             // 截取银行卡号后4位
@@ -623,7 +623,7 @@ if (!function_exists('format_bank_card')) {
             $format_card_no = $prefix . " **** **** **** " . $suffix;
         } else {
             // 4的意思就是每4个为一组
-            $arr            = str_split($card_no, 4);
+            $arr = str_split($card_no, 4);
             $format_card_no = implode(' ', $arr);
         }
         return $format_card_no;
@@ -673,7 +673,7 @@ if (!function_exists('get_username')) {
      * @param string $ext
      * @return string
      */
-    function get_username($id, $prefix = 'DYS')
+    function get_username($id, $prefix = 'U')
     {
         $length = strlen($id);
         if ($length >= 8) {
@@ -683,6 +683,22 @@ if (!function_exists('get_username')) {
     }
 }
 
+if (!function_exists('get_nickname')) {
+
+    /**
+     * 生成唯一字符串
+     * @param int $length
+     * @param string $prefix
+     * @param string $ext
+     * @return string
+     */
+    function get_nickname($prefix = 'T')
+    {
+        $mt = explode(' ', microtime());
+        return $prefix . time() . intval($mt[0] * 100);
+    }
+}
+
 if (!function_exists('get_password')) {
 
     /**
@@ -793,9 +809,9 @@ if (!function_exists('get_image_url')) {
             return '';
         }
 
-        if($domain){
-            $host = $domain.'/uploads';
-        }else{
+        if ($domain) {
+            $host = $domain . '/uploads';
+        } else {
             $host = request()->header('HOST');
             $https = request()->secure();
             $host = ($https ? 'https://' : 'http://') . $host . '/uploads';
@@ -845,7 +861,7 @@ if (!function_exists('get_format_images')) {
             $url = isset($v[$key]) ? $v[$key] : '';
             if ($url) {
                 $datas[] = [
-                    $key=> get_image_path($url)
+                    $key => get_image_path($url)
                 ];
             }
         }
@@ -876,7 +892,6 @@ if (!function_exists('get_web_url')) {
 }
 
 
-
 if (!function_exists('set_format_content')) {
 
     /**
@@ -891,19 +906,19 @@ if (!function_exists('set_format_content')) {
         }
 
         $domain = request()->header('HOST');
-        if(preg_match("/127/", $domain)){
-            $host = env('IMG_URL','');
-            if(empty($host)){
+        if (preg_match("/127/", $domain)) {
+            $host = env('IMG_URL', '');
+            if (empty($host)) {
                 $https = request()->secure();
                 $host = ($https ? 'https://' : 'http://') . $host . '/uploads';
             }
-        }else{
+        } else {
             $https = request()->secure();
             $host = ($https ? 'https://' : 'http://') . $domain . '/uploads';
         }
 
-        $content = str_replace("{$host}",'/uploads', htmlspecialchars_decode($content));
-        return  $content;
+        $content = str_replace("{$host}", '/uploads', htmlspecialchars_decode($content));
+        return $content;
     }
 }
 
@@ -922,19 +937,19 @@ if (!function_exists('get_format_content')) {
         }
 
         $domain = request()->header('HOST');
-        if(preg_match("/127/", $domain)){
-            $host = env('IMG_URL','');
-            if(empty($host)){
+        if (preg_match("/127/", $domain)) {
+            $host = env('IMG_URL', '');
+            if (empty($host)) {
                 $https = request()->secure();
                 $host = ($https ? 'https://' : 'http://') . $host . '/uploads';
             }
-        }else{
+        } else {
             $https = request()->secure();
             $host = ($https ? 'https://' : 'http://') . $domain . '/uploads';
         }
 
-        $content = str_replace(["\"/uploads","'/uploads"],["\"{$host}","'{$host}"], htmlspecialchars_decode($content));
-        return  $content;
+        $content = str_replace(["\"/uploads", "'/uploads"], ["\"{$host}", "'{$host}"], htmlspecialchars_decode($content));
+        return $content;
     }
 }
 
@@ -949,8 +964,8 @@ if (!function_exists('get_hash')) {
      */
     function get_hash()
     {
-        $chars   = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
-        $random  = $chars[mt_rand(0, 73)] . $chars[mt_rand(0, 73)] . $chars[mt_rand(0, 73)]
+        $chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()+-';
+        $random = $chars[mt_rand(0, 73)] . $chars[mt_rand(0, 73)] . $chars[mt_rand(0, 73)]
             . $chars[mt_rand(0, 73)] . $chars[mt_rand(0, 73)];
         $content = uniqid() . $random;
         return sha1($content);
@@ -1015,7 +1030,7 @@ if (!function_exists('get_client_ip')) {
         }
         // IP地址合法验证
         $long = sprintf("%u", ip2long($ip));
-        $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
+        $ip = $long ? array($ip, $long) : array('0.0.0.0', 0);
         return $ip[$type];
     }
 
@@ -1039,7 +1054,7 @@ if (!function_exists('get_guid_v4')) {
         }
         // OSX/Linux
         if (function_exists('openssl_random_pseudo_bytes') === true) {
-            $data    = openssl_random_pseudo_bytes(16);
+            $data = openssl_random_pseudo_bytes(16);
             $data[6] = chr(ord($data[6]) & 0x0f | 0x40);    // set version to 0100
             $data[8] = chr(ord($data[8]) & 0x3f | 0x80);    // set bits 6-7 to 10
             return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
@@ -1120,8 +1135,8 @@ if (!function_exists('is_idcard')) {
      */
     function is_idcard($idno)
     {
-        $idno      = strtoupper($idno);
-        $regx      = '/(^\d{15}$)|(^\d{17}([0-9]|X)$)/';
+        $idno = strtoupper($idno);
+        $regx = '/(^\d{15}$)|(^\d{17}([0-9]|X)$)/';
         $arr_split = array();
         if (!preg_match($regx, $idno)) {
             return false;
@@ -1148,14 +1163,14 @@ if (!function_exists('is_idcard')) {
                 // 检验18位身份证的校验码是否正确。
                 // 校验位按照ISO 7064:1983.MOD 11-2的规定生成,X可以认为是数字10。
                 $arr_int = array(7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2);
-                $arr_ch  = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
-                $sign    = 0;
+                $arr_ch = array('1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2');
+                $sign = 0;
                 for ($i = 0; $i < 17; $i++) {
-                    $b    = (int)$idno[$i];
-                    $w    = $arr_int[$i];
+                    $b = (int)$idno[$i];
+                    $w = $arr_int[$i];
                     $sign += $b * $w;
                 }
-                $n       = $sign % 11;
+                $n = $sign % 11;
                 $val_num = $arr_ch[$n];
                 if ($val_num != substr($idno, 17, 1)) {
                     return false;
@@ -1345,7 +1360,7 @@ if (!function_exists('showJson')) {
         } else {
             $result['code'] = $code ? $code : -1;
         }
-        return $type=='json'?response()->json($result, 200, [])->setEncodingOptions(256):$result;
+        return $type == 'json' ? response()->json($result, 200, [])->setEncodingOptions(256) : $result;
     }
 }
 
@@ -1360,8 +1375,8 @@ if (!function_exists('num2rmb')) {
      */
     function num2rmb($num)
     {
-        $c1  = "零壹贰叁肆伍陆柒捌玖";
-        $c2  = "分角元拾佰仟万拾佰仟亿";
+        $c1 = "零壹贰叁肆伍陆柒捌玖";
+        $c2 = "分角元拾佰仟万拾佰仟亿";
         $num = round($num, 2);
         $num = $num * 100;
         if (strlen($num) > 10) {
@@ -1382,23 +1397,23 @@ if (!function_exists('num2rmb')) {
             } else {
                 $c = $p1 . $c;
             }
-            $i   = $i + 1;
+            $i = $i + 1;
             $num = $num / 10;
             $num = (int)$num;
             if ($num == 0) {
                 break;
             }
         }
-        $j    = 0;
+        $j = 0;
         $slen = strlen($c);
         while ($j < $slen) {
             $m = substr($c, $j, 6);
             if ($m == '零元' || $m == '零万' || $m == '零亿' || $m == '零零') {
-                $left  = substr($c, 0, $j);
+                $left = substr($c, 0, $j);
                 $right = substr($c, $j + 3);
-                $c     = $left . $right;
-                $j     = $j - 3;
-                $slen  = $slen - 3;
+                $c = $left . $right;
+                $j = $j - 3;
+                $slen = $slen - 3;
             }
             $j = $j + 3;
         }
@@ -1470,8 +1485,8 @@ if (!function_exists('strip_html_tags')) {
         // 将空格替换成空
         $str = str_replace("&nbsp;", "", $str);
         // 函数剥去字符串中的 HTML、XML 以及 PHP 的标签,获取纯文本内容
-        $str  = strip_tags($str);
-        $str  = str_replace(array("\n", "\r\n", "\r"), ' ', $str);
+        $str = strip_tags($str);
+        $str = str_replace(array("\n", "\r\n", "\r"), ' ', $str);
         $preg = '/<script[\s\S]*?<\/script>/i';
         // 剥离JS代码
         $str = preg_replace($preg, "", $str, -1);
@@ -1504,10 +1519,10 @@ if (!function_exists('sub_str')) {
         } elseif (function_exists('iconv_substr')) {
             $slice = iconv_substr($str, $start, $length, $charset);
         } else {
-            $re['utf-8']  = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
+            $re['utf-8'] = "/[\x01-\x7f]|[\xc2-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf]{2}|[\xf0-\xff][\x80-\xbf]{3}/";
             $re['gb2312'] = "/[\x01-\x7f]|[\xb0-\xf7][\xa0-\xfe]/";
-            $re['gbk']    = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
-            $re['big5']   = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
+            $re['gbk'] = "/[\x01-\x7f]|[\x81-\xfe][\x40-\xfe]/";
+            $re['big5'] = "/[\x01-\x7f]|[\x81-\xfe]([\x40-\x7e]|\xa1-\xfe])/";
             preg_match_all($re[$charset], $str, $match);
             $slice = join("", array_slice($match[0], $start, $length));
         }
@@ -1533,7 +1548,7 @@ if (!function_exists('save_image')) {
             return false;
         }
         $save_dir = trim($save_dir, "/");
-        $imgExt   = pathinfo($img_url, PATHINFO_EXTENSION);
+        $imgExt = pathinfo($img_url, PATHINFO_EXTENSION);
 
 
         // 是否是本站图片
@@ -1732,12 +1747,12 @@ if (!function_exists('upload_image')) {
         // 返回结果
         $result = [
             'img_original_name' => $original_name,
-            'img_ext'           => $ext,
-            'img_real_path'     => $real_path,
-            'img_type'          => $type,
-            'img_size'          => $size,
-            'img_name'          => $file_name,
-            'img_path'          => $file_path,
+            'img_ext' => $ext,
+            'img_real_path' => $real_path,
+            'img_type' => $type,
+            'img_size' => $size,
+            'img_name' => $file_name,
+            'img_path' => $file_path,
         ];
         return message(MESSAGE_OK, true, $result);
     }
@@ -1809,12 +1824,12 @@ if (!function_exists('upload_file')) {
         // 返回结果
         $result = [
             'file_original_name' => $original_name,
-            'file_ext'           => $ext,
-            'file_real_path'     => $real_path,
-            'file_type'          => $type,
-            'file_size'          => $size,
-            'file_name'          => $file_name,
-            'file_path'          => $file_path,
+            'file_ext' => $ext,
+            'file_real_path' => $real_path,
+            'file_type' => $type,
+            'file_size' => $size,
+            'file_name' => $file_name,
+            'file_path' => $file_path,
         ];
         return message(MESSAGE_OK, true, $result);
     }
@@ -1885,12 +1900,12 @@ if (!function_exists('upload_video')) {
         // 返回结果
         $result = [
             'file_original_name' => $original_name,
-            'file_ext'           => $ext,
-            'file_real_path'     => $real_path,
-            'file_type'          => $type,
-            'file_size'          => $size,
-            'file_name'          => $file_name,
-            'file_path'          => $file_path,
+            'file_ext' => $ext,
+            'file_real_path' => $real_path,
+            'file_type' => $type,
+            'file_size' => $size,
+            'file_name' => $file_name,
+            'file_path' => $file_path,
         ];
         return message(MESSAGE_OK, true, $result);
     }
@@ -1946,7 +1961,7 @@ if (!function_exists('get_tree')) {
                 $tempArr[] = $data;
             } else if ($currentPid == 0 && $pid == 0) {
                 $data['children'] = get_tree($datas, $v['id'], []);
-                $tempArr[$id]     = $data;
+                $tempArr[$id] = $data;
             }
         }
 
@@ -1957,25 +1972,107 @@ if (!function_exists('get_tree')) {
 if (!function_exists('getSign')) {
     function getSign($data, $key = '')
     {
-        if (!is_array($data) || empty($data)) {
-            return false;
+        if (isset($data['system'])) {
+            unset($data['system']);
         }
 
-        $str = arrayToStr($data);
+        $str = $data? json_encode($data) : '';
+
         // 拼接密钥
-        $str .= '&key=' . ($key ? $key : md5(env('APP_SIGN_KEY', 'dysapp')));
-        $str = htmlspecialchars_decode($str);
+        $str .= '&key=' . ($key ? $key : env('APP_SIGN_KEY', 'app'));
+
 
         // MD5 运算
-//        var_dump($str);
         $sign = md5($str);
-        $sign .= substr($sign, 6, 4);
+        $sign = md5($sign . substr($sign, 0, 4)) . substr($sign, 2, 4);
+
         $sign = strtoupper($sign);
 
         return $sign;
     }
 }
 
+
+if (!function_exists('getStar')) {
+    /**
+     * 获取星座
+     * @param $date 生日:年-月-日
+     * @return string|string[]
+     */
+    function getStar($date)
+    {
+        if (!$date) {
+            return '';
+        }
+
+        $data = explode('-', $date);
+        $month = isset($data[1]) ? $data[1] : 0;
+        $day = isset($data[2]) ? $data[2] : 0;
+        $date = floatval(intval($month) . '.' . $day);
+        if ($date >= 1.20 && $date <= 2.18) {
+            return [
+                "name" => '水瓶座',
+                "code" => 'shuiping'
+            ];
+        } else if ($date >= 2.19 && $date <= 3.20) {
+            return [
+                "name" => '双鱼座',
+                "code" => 'shuangyu'
+            ];
+        } else if ($date >= 3.21 && $date <= 4.19) {
+            return [
+                "name" => '白羊座',
+                "code" => 'baiyang'
+            ];
+        } else if ($date >= 4.20 && $date <= 5.20) {
+            return [
+                "name" => '金牛座',
+                "code" => 'jinniu'
+            ];
+        } else if ($date >= 5.21 && $date <= 6.21) {
+            return [
+                "name" => '双子座',
+                "code" => 'shuangzi'
+            ];
+        } else if ($date >= 6.22 && $date <= 7.22) {
+            return [
+                "name" => '巨蟹座',
+                "code" => 'juxie'
+            ];
+        } else if ($date >= 7.23 && $date <= 8.22) {
+            return [
+                "name" => '狮子座',
+                "code" => 'shizi'
+            ];
+        } else if ($date >= 8.23 && $date <= 9.22) {
+            return [
+                "name" => '处女座',
+                "code" => 'chunv'
+            ];
+        } else if ($date >= 9.23 && $date <= 10.23) {
+            return [
+                "name" => '天秤座',
+                "code" => 'tianping'
+            ];
+        } else if ($date >= 10.24 && $date <= 11.22) {
+            return [
+                "name" => '天蝎座',
+                "code" => 'tianxie'
+            ];
+        } else if ($date >= 11.23 && $date <= 12.21) {
+            return [
+                "name" => '射手座',
+                "code" => 'sheshou'
+            ];
+        } else if ($date >= 12.22 || $date <= 1.19) {
+            return [
+                "name" => '摩羯座',
+                "code" => 'mojie'
+            ];
+        }
+    }
+}
+
 // 获取图片数组预览
 if (!function_exists('get_images_preview')) {
     /**
@@ -2008,10 +2105,10 @@ if (!function_exists('arrayToStr')) {
         $string = '';
         if (!empty($params)) {
             ksort($params, SORT_REGULAR);
-            $array = array();
+            $array = [];
 
             foreach ($params as $key => &$value) {
-                if($key != 'sign'){
+                if ($key != 'sign') {
                     // 过滤无法匹配校验的参数类型
                     if ($value !== false && $value != 'undefined' && !is_array($value) && !preg_match("/^[0-9]{1,9}\.[0-9]{8,}$/", $value)) {
                         $array[] = $key . '=' . trim($value);
@@ -2033,7 +2130,7 @@ if (!function_exists('arrayToUrl')) {
             $array = array();
             foreach ($params as $key => $value) {
                 if ($value != 'undefined') {
-                    $array[] = $key . '=' . (is_array($value) ? json_encode($value,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE) : $value);
+                    $array[] = $key . '=' . (is_array($value) ? json_encode($value, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) : $value);
                 }
             }
             $string = implode("&", $array);
@@ -2053,13 +2150,13 @@ if (!function_exists('httpRequest')) {
      * @return mixed
      * @author wesmiler
      */
-    function httpRequest($url, $data = '', $type = 'post', $cookie = '', $timeout = 60, $header=[])
+    function httpRequest($url, $data = '', $type = 'post', $cookie = '', $timeout = 60, $header = [])
     {
         try {
             set_time_limit($timeout);
             $data = $data && is_array($data) ? http_build_query($data) : $data;
-            $url  = strtolower($type) == 'get' ? $url . (strpos($url, '?') === false ? '?' : '&') . $data : $url;
-            $ch   = curl_init($url);
+            $url = strtolower($type) == 'get' ? $url . (strpos($url, '?') === false ? '?' : '&') . $data : $url;
+            $ch = curl_init($url);
             if (!empty($cookie)) {
                 curl_setopt($ch, CURLOPT_COOKIE, $cookie);
             }
@@ -2156,7 +2253,7 @@ if (!function_exists('moneyFormat')) {
     }
 }
 
-if(!function_exists('getChatKey')){
+if (!function_exists('getChatKey')) {
     /**
      * 获取聊天窗口KEY
      * @param $fromUserId
@@ -2165,7 +2262,7 @@ if(!function_exists('getChatKey')){
      */
     function getChatKey($fromUserId, $toUserId)
     {
-        if(empty($fromUserId) || empty($toUserId)){
+        if (empty($fromUserId) || empty($toUserId)) {
             return false;
         }
 
@@ -2175,7 +2272,7 @@ if(!function_exists('getChatKey')){
     }
 }
 
-if(!function_exists('getDistance')) {
+if (!function_exists('getDistance')) {
     /**
      * 计算地图坐标距离
      * @param $lat
@@ -2203,16 +2300,17 @@ if(!function_exists('getDistance')) {
     }
 }
 
-if(!function_exists('getParents')){
+if (!function_exists('getParents')) {
     /**
      * 获取分销上级用户ID
      * @param $parents
      * @return array|false
      */
-    function getParents($parents, $level=3){
-        $parents = $parents? explode(',', $parents) : [];
+    function getParents($parents, $level = 3)
+    {
+        $parents = $parents ? explode(',', $parents) : [];
         $parents = array_filter($parents);
-        if(empty($parents)){
+        if (empty($parents)) {
             return false;
         }
 
@@ -2221,12 +2319,13 @@ if(!function_exists('getParents')){
     }
 }
 
-if(!function_exists('getMillSecondTime')){
+if (!function_exists('getMillSecondTime')) {
     /**
      * 获取毫秒时间戳
      * @return float
      */
-    function getMillSecondTime() {
+    function getMillSecondTime()
+    {
         list($msec, $sec) = explode(' ', microtime());
         return (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
     }

+ 133 - 26
app/Http/Controllers/Api/LoginController.php

@@ -3,7 +3,12 @@
 namespace App\Http\Controllers\Api;
 
 use App\Helpers\Jwt;
+use App\Http\Validator\MemberValidator;
+use App\Services\Api\MemberService;
+use App\Services\ConfigService;
+use App\Services\EmailService;
 use App\Services\RedisService;
+use App\Services\SmsService;
 
 /**
  * 授权登录控制器基类
@@ -16,47 +21,149 @@ class LoginController extends webApp
      * 用户登录
      * @return array
      */
-    public function login(){
-        $code = request()->all();
-        if(empty($code)){
-            return message('code参数错误',false);
+    public function login()
+    {
+        $params = request()->all();
+        $account = isset($params['account']) ? $params['account'] : '';
+        $type = isset($params['type']) && $params['type'] ? $params['type'] : 1;
+        if (empty($account)) {
+            return message("210{$type}", false);
+        }
+
+        if (!in_array($type, [1, 2, 3])) {
+            return message("登录类型暂不支持", false);
         }
 
         // 授权
-        $openid = isset($this->userInfo['openid'])? $this->userInfo['openid'] : '';
-        $status = isset($this->userInfo['status'])? $this->userInfo['status'] : '';
-        $userId = isset($this->userInfo['id'])? $this->userInfo['id'] : 0;
-        if(empty($this->userInfo) || empty($openid) || $userId<=0){
-            return message('用户授权失败',false);
+        if ($res = MemberService::make()->login($params)) {
+            return showJson('登录成功', true, $res);
+        } else {
+            return showJson(MemberService::make()->getError(), false);
         }
+    }
 
-        if($status != 1){
-            return message('用户账户已被冻结不可操作',false);
+    /**
+     * 邀请注册账号
+     * @return array
+     */
+    public function register()
+    {
+        $params = request()->all();
+        $account = isset($params['account']) ? $params['account'] : '';
+        $incode = isset($params['incode']) ? $params['incode'] : '';
+        $type = isset($params['type']) && $params['type'] ? $params['type'] : 1;
+        if (empty($account)) {
+            return message("210{$type}", false);
         }
 
-        // 获取授权TOKEN
-        $jwt = new Jwt('jwt_wx');
-        $token = $jwt->getToken($userId, 3);
+        if(empty($incode)){
+            return message("请填写邀请码", false);
+        }
 
-        // 结果返回
-        $result = [
-            'access_token' => $token,
-            'info'=> $this->userInfo,
-        ];
+        if (!in_array($type, [1, 2, 3])) {
+            return message("账号类型暂不支持", false);
+        }
 
-        // 用户信息
-        RedisService::set("auths:info:{$userId}", $this->userInfo, 4*24*3600);
-        return message('获取授权成功', true, $result);
+        // 授权
+        if ($res = MemberService::make()->register($params)) {
+            return showJson('注册成功,请下载APP后登录使用', true, $res);
+        } else {
+            return showJson(MemberService::make()->getError(), false);
+        }
     }
 
-    public function register()
+    /**
+     * 修改账号信息
+     * @param MemberValidator $validator
+     * @return array
+     */
+    public function forget(MemberValidator $validator)
+    {
+        $params = request()->all();
+        $params = $validator->check($params, 'modify_password');
+        if (!is_array($params)) {
+            return showJson($params, false);
+        }
+
+        if(!MemberService::make()->forget($params)){
+            $error = MemberService::make()->getError();
+            return showJson($error,false,'',$error==1040?405:0);
+        }else{
+            return showJson(MemberService::make()->getError(),true);
+        }
+    }
+
+    /**
+     * 发送短信验证码
+     * @return array
+     */
+    public function smsSend(MemberValidator $validator)
     {
+        $params = request()->all();
+        $params = $validator->check($params, 'sms');
+        $appSources = isset($params['app_sources']) ? $params['app_sources'] : '';
+        if (!is_array($params)) {
+            return showJson($params, false);
+        }
+
+        // 发送验证码处理
+        $mobile = isset($params['account']) ? $params['account'] : '';
+        $scene = isset($params['scene']) ? $params['scene'] : '';
+        switch ($scene) {
+            case 'reg':
+                if (MemberService::make()->checkExists('mobile', $mobile)) {
+                    return showJson(1035, false,'', 406);
+                }
+                break;
+            case 'modify_mobile':
+                if (MemberService::make()->checkExists('mobile', $mobile)) {
+                    return showJson(1035, false,'', 406);
+                }
+                break;
+            case 'reset_password':
+        }
+
+        if (!SmsService::make()->send($mobile, $scene)) {
+            return showJson(SmsService::make()->getError(), false);
+        }
 
+        return showJson(1011, true);
     }
 
-    public function sendmsm()
+    /**
+     * 发送邮箱验证码
+     * @return array
+     */
+    public function emailSend(MemberValidator $validator)
     {
-        $username = request()->post('username');
-        return message(1011, true);
+        $params = request()->all();
+        $params = $validator->check($params, 'email');
+        $appSources = isset($params['app_sources']) ? $params['app_sources'] : '';
+        if (!is_array($params)) {
+            return showJson($params, false);
+        }
+
+        // 发送验证码处理
+        $email = isset($params['account']) ? $params['account'] : '';
+        $scene = isset($params['scene']) ? $params['scene'] : '';
+        switch ($scene) {
+            case 'reg':
+                if (MemberService::make()->checkExists('email', $email)) {
+                    return showJson(2009, false, ['app_url' => ConfigService::make()->getConfigByCode("app_{$appSources}_url"),], 406);
+                }
+                break;
+            case 'modify_email':
+                if (MemberService::make()->checkExists('email', $email)) {
+                    return showJson(2009, false, ['app_url' => ConfigService::make()->getConfigByCode("app_{$appSources}_url"),], 406);
+                }
+                break;
+            case 'reset_password':
+        }
+
+        if (!EmailService::make()->send($email, $scene)) {
+            return showJson(EmailService::make()->getError(), false);
+        }
+
+        return showJson(2020, true);
     }
 }

+ 96 - 0
app/Http/Controllers/Api/v1/IndexController.php

@@ -0,0 +1,96 @@
+<?php
+
+namespace App\Http\Controllers\Api\v1;
+
+use App\Http\Controllers\Api\webApp;
+use App\Services\Api\ArticleService;
+use App\Services\Api\MemberService;
+use App\Services\Api\PledgeOrderService;
+use App\Services\Api\PriceLogService;
+use App\Services\Common\AdService;
+use App\Services\ConfigService;
+use App\Services\RedisService;
+
+/**
+ * 首页
+ * @package App\Http\Controllers\Api\v1
+ */
+class IndexController extends webApp
+{
+    /**
+     * 首页数据
+     * @return array
+     */
+    public function data()
+    {
+        $cacheKey = "caches:index:data";
+        $data = RedisService::get($cacheKey);
+        if(empty($data)) {
+            $sbtLimit = ConfigService::make()->getConfigByCode('sbt_exchange_limit', 100);
+            $sbtPrice = PriceLogService::make()->getSbtPrice();
+            $sbtLimit = round($sbtLimit/$sbtPrice, 2);
+            $sbtLimit = $sbtLimit>0? $sbtLimit : 0;
+            $data = [
+                'profile' => MemberService::make()->getProfile($this->userId),
+                'banners' => AdService::make()->getListByType(1,'zh',6),
+                'siteInfo' => [
+                    'site_name' => ConfigService::make()->getConfigByCode('site_name', 'SBT'),
+                    'site_title' => ConfigService::make()->getConfigByCode('site_name', 'SBT'),
+                    'logo' => get_image_url(ConfigService::make()->getConfigByCode('site_logo', '/images/logo.png')),
+                    'exchange_sbt_fee' => ConfigService::make()->getConfigByCode('exchange_sbt_fee', 0),
+                    'sbt_exchange_limit'=> $sbtLimit,
+                    'version'=> ConfigService::make()->getConfigByCode('app_version', 'v1.2.10'),
+                ],
+            ];
+
+            RedisService::set($cacheKey, $data, rand(30, 60));
+        }
+
+        return showJson(1010,true, $data);
+    }
+
+    /**
+     * 配置信息
+     * @return array
+     */
+    public function config()
+    {
+        try {
+            $params = request()->all();
+            $system = isset($params['system'])? $params['system'] : [];
+            $appSources = isset($system['app_sources']) && $system['app_sources']? $system['app_sources'] : 'android';
+            $cacheKey = "caches:config:app_{$appSources}";
+            $config = RedisService::get($cacheKey);
+            if ($config) {
+                return showJson(1010, true, $config);
+            }
+
+            $siteInfo = ConfigService::make()->getConfigByGroup(1);
+            $config = [
+                'app_name' => isset($siteInfo['app_name']['value'])? $siteInfo['app_name']['value'] : '',
+                'app_logo' => isset($siteInfo['app_logo']['value']) && $siteInfo['app_logo']['value']? get_image_url($siteInfo['app_logo']['value']) : '',
+                'app_version' => isset($siteInfo['app_version']['value'])? $siteInfo['app_version']['value'] : '',
+                'app_sources' => $appSources,
+                'app_urls'=>[
+                    'android'=> isset($siteInfo['android_app_url']['value'])? $siteInfo['android_app_url']['value'] : '',
+                    'ios'=> isset($siteInfo['ios_app_url']['value'])? $siteInfo['ios_app_url']['value'] : '',
+                ]
+            ];
+            RedisService::set($cacheKey, $config, 120);
+            return showJson(1010, true, $config);
+        } catch (\Exception $exception) {
+            RedisService::set("caches:request:error_config", ['trace' => $exception->getTrace()], 7200);
+            return showJson(1018, false, ['error' => env('APP_DEBUG') ? $exception->getMessage() : '']);
+        }
+    }
+
+    /**
+     * SBD价格数据
+     * @return array
+     */
+    public function priceData(){
+        $dateType = request()->post('type', 1);
+        $refresh = request()->post('refresh', 0);
+        return showJson(1010,true, PriceLogService::make()->getCounts($dateType, $refresh));
+    }
+}

+ 113 - 0
app/Http/Controllers/Api/v1/MemberController.php

@@ -0,0 +1,113 @@
+<?php
+
+namespace App\Http\Controllers\Api\v1;
+
+use App\Http\Controllers\Api\webApp;
+use App\Services\Api\MemberService;
+use function Psy\sh;
+
+/**
+ * 会员
+ * @package App\Http\Controllers\Api\v1
+ */
+class MemberController extends webApp
+{
+
+    /**
+     * 用户信息
+     * @return array|mixed
+     */
+    public function info()
+    {
+        try {
+            $refresh = request()->post('refresh', false);
+            if($info = MemberService::make()->getInfo($this->userId, $refresh)){
+                return showJson(1010, true, $info);
+            }else{
+                return showJson(1009,false,'',403);
+            }
+        } catch (\Exception $exception){
+            return showJson(1036,false,['error'=>$exception->getMessage()],403);
+        }
+    }
+
+    /**
+     * 修改资料
+     * @return array
+     */
+    public function setProfile()
+    {
+        $params = request()->post();
+        if($info = MemberService::make()->setProfile($this->userId, $params)){
+            return showJson(MemberService::make()->getError(), true, $info);
+        }else{
+            return showJson(MemberService::make()->getError(),false);
+        }
+    }
+
+    /**
+     * 设置分红比例
+     * @return array
+     */
+    public function setBonus()
+    {
+        $params = request()->all();
+        if($info = MemberService::make()->setBonus($this->userId, $params)){
+            return showJson(MemberService::make()->getError(), true, $info);
+        }else{
+            return showJson(MemberService::make()->getError(),false, MemberService::make()->getErrorData());
+        }
+    }
+
+    /**
+     * 设置自动质押
+     * @return array
+     */
+    public function setPledge()
+    {
+        $params = request()->all();
+        if($info = MemberService::make()->setPledge($this->userId, $params)){
+            return showJson(MemberService::make()->getError(), true, $info);
+        }else{
+            return showJson(MemberService::make()->getError(),false);
+        }
+    }
+
+    /**
+     * 充值
+     * @return array
+     */
+    public function recharge()
+    {
+        return showJson(1009,false,'',403);
+    }
+
+    /**
+     * 提现
+     * @return array
+     */
+    public function withdraw()
+    {
+        $params = request()->post();
+        if($result = MemberService::make()->withdraw($this->userId, $params)){
+            return showJson(2027, true, $result);
+        }else{
+            return showJson(MemberService::make()->getError(),false, MemberService::make()->getErrorData());
+        }
+    }
+
+    /**
+     * 闪兑
+     * @return array
+     */
+    public function exchange()
+    {
+        $params = request()->post();
+        if($result = MemberService::make()->exchange($this->userId, $params)){
+            return showJson(2105, true, $result);
+        }else{
+            return showJson(MemberService::make()->getError(),false, MemberService::make()->getErrorData());
+        }
+    }
+
+}

+ 2 - 1
app/Http/Controllers/Api/webApp.php

@@ -54,8 +54,9 @@ class webApp extends BaseController
         // 初始化分页参数
         $this->initConfig();
 
+
         // 登录检测中间件
-        $this->middleware('web.login');
+//        $this->middleware('web.login');
 
 
         // 初始化登录信息

+ 4 - 4
app/Http/Middleware/WebLogin.php

@@ -26,8 +26,8 @@ class WebLogin extends Middleware
         $action = app('request')->route()->getAction();
         $controller = class_basename($action['controller']);
         list($controller, $action) = explode('@', $controller);
-        $noLoginActs = ['LoginController','TestController','NotifyController','IndexController','ArticleController','UploadController','TaskController'];
-        $noSignActions = ['UploadController','setAvatar','NotifyController','TestController','TaskController'];
+//        $noLoginActs = ['LoginController','TestController','NotifyController','IndexController','ArticleController','UploadController','TaskController'];
+//        $noSignActions = ['UploadController','setAvatar','NotifyController','TestController','TaskController'];
         $token = $request->headers->get('Authorization');
         if (strpos($token, 'Bearer ') !== false) {
             $token = str_replace("Bearer ", null, $token);
@@ -49,7 +49,7 @@ class WebLogin extends Middleware
         $sign = $request->headers->get('sign');
         $params = $request->except('s');
         $checkSign = getSign($params);
-        if($sign != 'test6688' && !in_array($action, $noSignActions) && !in_array($controller, $noSignActions)) {
+        if($sign != 'test6688') {
             if ($sign != $checkSign) {
                 return response()->json(message(1005, false, [], 403))->setEncodingOptions(256);
             }
@@ -61,7 +61,7 @@ class WebLogin extends Middleware
 
         }
 
-        if (!$userId && !in_array($controller, $noLoginActs)) {
+        if (!$userId && !in_array($controller,['LoginController','IndexController'])) {
             // 判断用户未登录就跳转至登录页面
             // 在这里可以定制你想要的返回格式, 亦或者是 JSON 编码格式
             return response()->json(message(1004, false, [], 403))->setEncodingOptions(256);

+ 3 - 1
app/Http/Validator/MemberValidator.php

@@ -31,7 +31,9 @@ class MemberValidator extends BaseValidator
     // 当前模型所有验证场景
     public static $scenes = [
         'info'=> ['id'],
-        'save'=> ['mobile','nickname','gender'],
+        'save'=> ['account','nickname','gender'],
+        'sms'=> ['account','scene'],
+        'email'=> ['account','scene'],
     ];
 
     /**

+ 24 - 0
app/Models/AdCallbackModel.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 广告回调记录表-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class AdCallbackModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'ad_callbacks';
+}

+ 24 - 0
app/Models/AdConfigModel.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 广告平台配置表-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class AdConfigModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'ad_configs';
+}

+ 24 - 0
app/Models/AdRecordModel.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 广告观看记录表-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class AdRecordModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'ad_records';
+}

+ 35 - 0
app/Models/DossierModel.php

@@ -0,0 +1,35 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 会员档案表-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class DossierModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'dossiers';
+
+    /**
+     * 分类
+     * @return \Illuminate\Database\Eloquent\Relations\HasOne
+     */
+    public function dossierType()
+    {
+        return $this->hasOne(DossierTypeModel::class, 'id','type')
+            ->where(['mark'=>1])
+            ->select(['id','name','sort','status']);
+    }
+}

+ 24 - 0
app/Models/DossierTypeModel.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 会员档案分类表-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class DossierTypeModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'dossiers_types';
+}

+ 24 - 0
app/Models/GoodsCategoryModel.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 商品分类表-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class GoodsCategoryModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'goods_category';
+}

+ 35 - 0
app/Models/GoodsModel.php

@@ -0,0 +1,35 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 商品-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class GoodsModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'goods';
+
+    /**
+     * 分类
+     * @return \Illuminate\Database\Eloquent\Relations\HasOne
+     */
+    public function goodsType()
+    {
+        return $this->hasOne(GoodsCategoryModel::class, 'id','cate_id')
+            ->where(['mark'=>1])
+            ->select(['id','cate_id','pid','name','sort','status']);
+    }
+}

+ 24 - 0
app/Models/GoodsSkuModel.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 商品规格表-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class GoodsSkuModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'goods_sku';
+}

+ 32 - 12
app/Models/MemberModel.php

@@ -24,6 +24,38 @@ class MemberModel extends BaseModel
     protected $table = 'member';
 
     /**
+     * 上级
+     * @return \Illuminate\Database\Eloquent\Relations\HasOne
+     */
+    public function parent()
+    {
+        return $this->hasOne(MemberModel::class, 'id','parent_id')
+            ->where(['mark'=>1])
+            ->select(['id','parent_id','nickname','code','status']);
+    }
+
+    /**
+     * 资料档案
+     * @return \Illuminate\Database\Eloquent\Relations\HasOne
+     */
+    public function profile()
+    {
+        return $this->hasOne(DossierModel::class, 'user_id','id')
+            ->where(['type'=>1,'status'=>1,'mark'=>1]);
+    }
+
+    /**
+     * 等级
+     * @return \Illuminate\Database\Eloquent\Relations\HasOne
+     */
+    public function level()
+    {
+        return $this->hasOne(MemberLevelModel::class, 'id','member_level')
+            ->where(['mark'=>1])
+            ->select(['id','name','upgrade','status']);
+    }
+
+    /**
      * 获取会员信息
      * @param int $id 会员ID
      * @return array|string
@@ -38,18 +70,6 @@ class MemberModel extends BaseModel
             if ($info['avatar']) {
                 $info['avatar'] = get_image_url($info['avatar']);
             }
-            // 出生日期
-            if ($info['birthday']) {
-                $info['birthday'] = datetime($info['birthday']);
-            }
-            // 城市
-            if ($info['province_id'] && $info['city_id'] && $info['district_id']) {
-                $city = [];
-                $city[] = $info['province_id'];
-                $city[] = $info['city_id'];
-                $city[] = $info['district_id'];
-                $info['city'] = $city;
-            }
         }
         return $info;
     }

+ 24 - 0
app/Models/OrderGoodsModel.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 订单商品表-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class OrderGoodsModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'orders_goods';
+}

+ 24 - 0
app/Models/OrderModel.php

@@ -0,0 +1,24 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Models;
+
+/**
+ * 订单表-模型
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Models
+ */
+class OrderModel extends BaseModel
+{
+    // 设置数据表
+    protected $table = 'orders';
+}

+ 974 - 0
app/Services/Api/GoodsService.php

@@ -0,0 +1,974 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Services\Api;
+
+use App\Models\GoodsCategoryModel;
+use App\Models\GoodsModel;
+use App\Models\GoodsSkuModel;
+use App\Models\OrderModel;
+use App\Services\BaseService;
+use App\Services\ConfigService;
+use App\Services\RedisService;
+use App\Services\SupplyService;
+use Illuminate\Support\Facades\DB;
+
+/**
+ * 商品管理-服务类
+ * @author laravel开发员
+ * @since 2020/11/11
+ * Class GoodsService
+ * @package App\Services\Api
+ */
+class GoodsService extends BaseService
+{
+    // 静态对象
+    protected static $instance = null;
+
+    /**
+     * 构造函数
+     * @author laravel开发员
+     * @since 2020/11/11
+     * GoodsService constructor.
+     */
+    public function __construct()
+    {
+        $this->model = new GoodsModel();
+    }
+
+    /**
+     * 静态入口
+     * @return static|null
+     */
+    public static function make()
+    {
+        if (!self::$instance) {
+            self::$instance = (new static());
+        }
+        return self::$instance;
+    }
+
+    /**
+     * 商品列表
+     * @param $params
+     * @param int $pageSize
+     * @param int $userId
+     * @return array
+     */
+    public function getDataList($params, $pageSize = 12, $userId = 0)
+    {
+        $model = $this->model->with(['skuList'])->from('goods as a')
+            ->where(['a.status' => 1, 'a.mark' => 1])
+            ->where('a.retail_price', '>', 0)
+            ->where(function ($query) use ($params) {
+                $supplyType = isset($params['supply_type']) ? intval($params['supply_type']) : 0;
+                if ($supplyType > 0) {
+                    $query->where('a.supply_type', $supplyType);
+                }
+
+                $cateId = isset($params['cate_id']) ? intval($params['cate_id']) : 0;
+                if ($cateId > 0) {
+                    $subIds = GoodsCategoryModel::where(['pid' => $cateId, 'mark' => 1, 'status' => 1])->pluck('cate_id');
+                    $query->where(function ($query) use ($cateId, $subIds) {
+                        if ($subIds) {
+                            $query->whereIn('a.cate_id', $subIds)
+                                ->orWhere('a.cate_id', $cateId);
+                        } else {
+                            $query->where('a.cate_id', $cateId);
+                        }
+                    });
+                }
+
+            })
+            ->where(function ($query) use ($params) {
+                $keyword = isset($params['kw']) ? $params['kw'] : '';
+                if ($keyword) {
+                    $query->where('a.goods_name', 'like', "%{$keyword}%")
+                        ->orWhere('a.spu_name', 'like', "%{$keyword}%")
+                        ->orWhere('a.tag', 'like', "%{$keyword}%");
+                }
+
+            })
+            ->select(['a.*']);
+
+        // 排序
+        $sortType = isset($params['sort_type']) ? $params['sort_type'] : 1;
+        if ($sortType == 2) {
+            $model = $model->orderBy('a.is_recommend', 'asc')->orderBy('a.sales', 'desc');
+        }
+
+
+        $list = $model->orderBy('a.create_time', 'desc')
+            ->paginate($pageSize > 0 ? $pageSize : 9999999);
+        $list = $list ? $list->toArray() : [];
+        if ($list) {
+            $locale     = RedisService::get("caches:locale:lang_{$userId}");
+            $locale     = $locale ? $locale : session('locale_lang');
+            $locale     = $locale ? $locale : 'zh-cn';
+            $supplyList = config('goods.supplyList');
+            $usdtPrice  = RedisService::get("caches:wallets:usdt_rate");
+            if ($usdtPrice <= 0) {
+                $usdtCnyPrice = ConfigService::make()->getConfigByCode('usdt_cny_price', 7.2);
+                $usdtPrice    = $usdtCnyPrice > 0 && $usdtCnyPrice < 100 ? $usdtCnyPrice : 0;
+            }
+
+            $xdPrice       = ConfigService::make()->getConfigByCode('xd_price', 100);
+            $xdPrice       = $xdPrice > 0 && $xdPrice <= 10000 ? $xdPrice : 100;
+            $awardWaitRate = ConfigService::make()->getConfigByCode('shop_award_score_rate', 0);
+            $awardWaitRate = $awardWaitRate > 0 && $awardWaitRate < 1000 ? $awardWaitRate : 0;
+            $waitRate      = ConfigService::make()->getConfigByCode('day_wait_score_rate', 0);
+            $waitRate      = $waitRate > 0 && $waitRate < 100 ? $waitRate : 0;
+            foreach ($list['data'] as &$item) {
+                $item['detail_img']    = isset($item['detail_img']) && $item['detail_img'] ? json_decode($item['detail_img'], true) : [];
+                $item['supply_name']   = isset($supplyList[$item['supply_type']]) ? $supplyList[$item['supply_type']] : '';
+                $item['usdt_price']    = $usdtPrice;
+                $item['xd_price_rate'] = $xdPrice;
+                $item['retail_price1'] = $item['retail_price'];
+                $item['retail_price']  = $this->getRealSalePrice($item['cost_price']);
+                $item['wait_score']    = moneyFormat($item['retail_price'] * $awardWaitRate / 100 * $waitRate / 100, 2);
+            }
+            unset($item);
+        }
+
+        return [
+            'total'    => isset($list['total']) ? $list['total'] : 9,
+            'pageSize' => $pageSize,
+            'list'     => isset($list['data']) ? $list['data'] : [],
+        ];
+    }
+
+    /**
+     * 详情
+     * @param $id
+     * @return array
+     */
+    public function getInfo($goodsId, $userId = 0, $updateView = true)
+    {
+        $field = ['a.*'];
+        $info  = $this->model->from('goods as a')->with(['category', 'skuList'])
+            ->where(['a.goods_id' => $goodsId, 'a.status' => 1, 'a.mark' => 1])
+            ->select($field)
+            ->first();
+        $info  = $info ? $info->toArray() : [];
+        if ($info) {
+            if (isset($info['main_img'])) {
+                $info['main_img'] = $info['main_img'] ? get_image_url($info['main_img']) : '';
+            }
+            if (isset($info['detail_img'])) {
+                $info['detail_img'] = $info['detail_img'] ? json_decode($info['detail_img'], true) : [];
+                $thumbs = [$info['main_img']];
+                $info['detail_img'] = $info['detail_img']? array_merge($thumbs,$info['detail_img']) : $thumbs;
+            }
+
+            if (empty($info['detail_img'])) {
+                $info['detail_img'] = [$info['main_img']];
+            }
+
+            $supplyList          = config('goods.supplyList');
+            $info['supply_name'] = isset($supplyList[$info['supply_type']]) ? $supplyList[$info['supply_type']] : '';
+
+            $usdtPrice = RedisService::get("caches:wallets:usdt_rate");
+            if ($usdtPrice <= 0) {
+                $usdtCnyPrice = ConfigService::make()->getConfigByCode('usdt_cny_price', 7.2);
+                $usdtPrice    = $usdtCnyPrice > 0 && $usdtCnyPrice < 100 ? $usdtCnyPrice : 0;
+            }
+            $xdPrice                 = ConfigService::make()->getConfigByCode('xd_price', 100);
+            $xdPrice                 = $xdPrice > 0 && $xdPrice <= 10000 ? $xdPrice : 100;
+            $info['usdt_price_rate'] = $usdtPrice;
+            $info['xd_price']        = $xdPrice;
+            $info['custom_uid']      = ConfigService::make()->getConfigByCode('xl_custom_id', 100001);
+            $awardWaitRate           = ConfigService::make()->getConfigByCode('shop_award_score_rate', 0);
+            $awardWaitRate           = $awardWaitRate > 0 && $awardWaitRate < 1000 ? $awardWaitRate : 0;
+            $waitRate                = ConfigService::make()->getConfigByCode('day_wait_score_rate', 0);
+            $waitRate                = $waitRate > 0 && $waitRate < 100 ? $waitRate : 0;
+            if (isset($info['retail_price']) && $info['retail_price']) {
+                $info['retail_price1'] = $info['retail_price'];
+                $info['retail_price']  = $this->getRealSalePrice($info['cost_price']);
+                $info['wait_score']    = moneyFormat($info['retail_price'] * $awardWaitRate / 100 * $waitRate / 100, 2);
+            }
+
+            if (isset($info['sku_list']) && $info['sku_list']) {
+                foreach ($info['sku_list'] as &$v) {
+                    $v['detail_img']     = $v['detail_img'] ? json_decode($v['detail_img'], true) : [];
+                    $v['attr']           = $v['attr'] ? json_decode($v['attr'], true) : [];
+                    $v['main_img']       = $v['main_img'] ? get_image_url($v['main_img']) : '';
+                    $v['retail_price_1'] = $v['retail_price'];
+                    $v['retail_price']   = $this->getRealSalePrice($v['plat_price']);
+                    $v['wait_score']  = moneyFormat($v['retail_price'] * $awardWaitRate / 100 * $waitRate / 100, 2);
+                }
+                unset($v);
+            }
+
+            // 更新访问量
+            if ($updateView) {
+                $this->updateView($userId, $goodsId);
+            }
+        }
+
+        return $info;
+
+    }
+
+    /**
+     * 实际售价
+     * @param $price 成本价或其他价格
+     * @param bool $float 是否浮动转换,1-浮动转换,2-不浮动转换,3-浮动不转换
+     * @return string
+     */
+    public function getRealSalePrice($price, $float = 1)
+    {
+        $usdtPrice = RedisService::get("caches:wallets:usdt_rate");
+        if ($usdtPrice <= 0) {
+            $usdtCnyPrice = ConfigService::make()->getConfigByCode('usdt_cny_price', 7.2);
+            $usdtPrice    = $usdtCnyPrice > 0 && $usdtCnyPrice < 100 ? $usdtCnyPrice : 0;
+        }
+        $xdPrice   = ConfigService::make()->getConfigByCode('xd_price', 100);
+        $xdPrice   = $xdPrice > 0 && $xdPrice <= 10000 ? $xdPrice : 100;
+        $floatRate = ConfigService::make()->getConfigByCode('goods_price_float_rate', 0);
+        $floatRate = $floatRate > 0 && $floatRate < 100 ? $floatRate : 0;
+        $price     = $float == 2 ? $price : floatval($price * (1 + ($floatRate / 100)));
+        if ($float == 3) {
+            return $price;
+        }
+        return $usdtPrice > 0 ? moneyFormat($price / $usdtPrice * $xdPrice, 2) : $price;
+    }
+
+    /**
+     * 获取要购买或结算的商品列表
+     * @param $userId
+     * @param array $params
+     * @return array|false|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection
+     */
+    public function getBuyList($userId, $params = [])
+    {
+        $goodsId = isset($params['goods_id']) ? $params['goods_id'] : 0;
+        $skuId   = isset($params['sku_id']) ? $params['sku_id'] : 0;
+        $num     = isset($params['num']) ? $params['num'] : 0;
+        $cartIds = isset($params['cart_ids']) ? $params['cart_ids'] : '';
+        $cartIds = $cartIds ? explode('|', $cartIds) : [];
+        if (empty($goodsId) && empty($cartIds)) {
+            $this->error = 2901;
+            return false;
+        }
+
+        if ($goodsId && (empty($skuId) || $num <= 0)) {
+            $this->error = 2901;
+            return false;
+        }
+
+        $cacheKey = "caches:goods:buyList:{$userId}_" . md5(json_encode($params, 256));
+        $datas    = RedisService::get($cacheKey);
+        if ($datas) {
+            return $datas;
+        }
+
+        $goods     = [];
+        $skuList   = [];
+        $usdtPrice = RedisService::get("caches:wallets:usdt_rate");
+        if ($usdtPrice <= 0) {
+            $usdtCnyPrice = ConfigService::make()->getConfigByCode('usdt_cny_price', 7.2);
+            $usdtPrice    = $usdtCnyPrice > 0 && $usdtCnyPrice < 100 ? $usdtCnyPrice : 0;
+        }
+        $xdPrice = ConfigService::make()->getConfigByCode('xd_price', 100);
+        $xdPrice = $xdPrice > 0 && $xdPrice <= 10000 ? $xdPrice : 100;
+
+        if ($goodsId) {
+            $info = $this->getInfo($goodsId, $userId, false);
+            if ($info) {
+
+                $info['num']    = $num;
+                $info['sku_id'] = $skuId;
+                $skuInfo        = GoodsSkuModel::where(['goods_id' => $goodsId, 'sku_id' => $skuId, 'mark' => 1])->first();
+                $price          = isset($skuInfo['plat_price']) ? $skuInfo['plat_price'] : 0;
+                if ($price) {
+                    $info['retail_price1'] = $info['retail_price'];
+                    $info['retail_price']  = $this->getRealSalePrice($price);
+                }
+
+                if (isset($skuInfo['attr']) && $skuInfo['attr']) {
+                    $skuInfo['attr'] = json_decode($skuInfo['attr'], true);
+                }
+
+                $skuList[$goodsId] = [
+                    'sku_id' => $skuId,
+                    'num'    => $num
+                ];
+                $info['sku']       = $skuInfo;
+                $goods[]           = $info;
+            }
+        } else {
+            $goods = CartsModel::with(['sku'])->from('carts as a')
+                ->leftJoin('goods as b', 'b.goods_id', '=', 'a.goods_id')
+                ->leftJoin('goods_sku as c', 'c.sku_id', '=', 'a.sku_id')
+                ->whereIn('a.id', $cartIds)
+                ->where(['a.status' => 1, 'a.mark' => 1, 'b.status' => 1, 'b.mark' => 1])
+                ->where('b.retail_price', '>', 0)
+                ->where('a.num', '>', 0)
+                ->select(['b.goods_id', 'b.merch_id', 'b.goods_name', 'b.supply_type', 'b.main_img', 'b.cost_price', 'b.retail_price', 'b.limit_num', 'b.lowest_num', 'b.brand_name', 'a.num', 'a.sku_id'])
+                ->get();
+            if ($goods) {
+
+                // 价格等参数格式化
+                $locale     = RedisService::get("caches:locale:lang_{$userId}");
+                $locale     = $locale ? $locale : session('locale_lang');
+                $locale     = $locale ? $locale : 'zh-cn';
+                $supplyList = config('goods.supplyList');
+
+                foreach ($goods as &$item) {
+                    $item['detail_img']    = isset($item['detail_img']) && $item['detail_img'] ? json_decode($item['detail_img'], true) : [];
+                    $item['supply_name']   = isset($supplyList[$item['supply_type']]) ? $supplyList[$item['supply_type']] : '';
+                    $item['usdt_price']    = $usdtPrice;
+                    $item['xd_price_rate'] = $xdPrice;
+                    $item['retail_price1'] = $item['retail_price'];
+                    $skuInfo               = isset($item['sku']) ? $item['sku'] : [];
+                    if (isset($skuInfo['attr']) && $skuInfo['attr']) {
+                        $skuInfo['attr'] = json_decode($skuInfo['attr'], true);
+                    }
+                    $item['sku'] = $skuInfo;
+                    $price       = isset($skuInfo['plat_price']) ? $skuInfo['plat_price'] : 0;
+                    if ($price) {
+                        $item['retail_price'] = $this->getRealSalePrice($price);
+                    } else {
+                        $item['retail_price'] = $this->getRealSalePrice($item['cost_price']);
+                    }
+                    $skuList[$item['goods_id']] = [
+                        'sku_id' => $item['sku_id'],
+                        'num'    => $item['num']
+                    ];
+                }
+                unset($item);
+            }
+        }
+
+        if (empty($goods)) {
+            $this->error = 2901;
+            return false;
+        }
+
+        RedisService::set($cacheKey, ['sku_list' => array_values($skuList), 'goods' => $goods], rand(2, 3));
+        return ['sku_list' => array_values($skuList), 'goods' => $goods];
+    }
+
+    /**
+     * 订单商品
+     * @param $userId
+     * @param $ids
+     * @return array
+     */
+    public function getOrderGoods($userId, $ids)
+    {
+        $cacheKey = "caches:goodsOrder:{$userId}_" . md5(json_encode($ids, 256));
+        $datas    = RedisService::get($cacheKey);
+        if ($datas) {
+            return $datas;
+        }
+
+        $goods = $this->model->from('goods as a')
+            ->whereIn('a.goods_id', $ids)
+            ->where(['a.status' => 1, 'a.mark' => 1])
+            ->where('a.retail_price', '>', 0)
+            ->select(['a.goods_id', 'a.merch_id', 'a.goods_name', 'a.cate_id', 'a.supply_type', 'a.main_img', 'a.cost_price', 'a.retail_price'])
+            ->get();
+        $goods = $goods ? $goods->toArray() : [];
+        if ($goods) {
+            RedisService::set($cacheKey, $goods, rand(5, 10));
+        }
+        return $goods;
+    }
+
+    /**
+     * 添加/更新购物车
+     * @param $userId
+     * @param $goodsId
+     * @param $params
+     * @return array|false
+     */
+    public function updateCart($userId, $goodsId, $params)
+    {
+        $skuId   = isset($params['sku_id']) ? $params['sku_id'] : 0;
+        $status  = isset($params['status']) ? $params['status'] : 0;
+        $merchId = isset($params['merch_id']) ? $params['merch_id'] : 0;
+        $num     = isset($params['num']) ? $params['num'] : 1;
+        if ($skuId <= 0 || $goodsId <= 0 || $userId <= 0 || $num <= 0) {
+            $this->error = 2014;
+            return false;
+        }
+
+        if (CartsModel::where(['user_id' => $userId, 'status' => 1, 'mark' => 1])->count('id') > 20) {
+            $this->error = 1050;
+            return false;
+        }
+
+        $cartId = CartsModel::where(['user_id' => $userId, 'goods_id' => $goodsId, 'sku_id' => $skuId])->value('id');
+        if ($cartId) {
+            CartsModel::where(['id' => $cartId])->update(['num' => $num, 'merch_id' => $merchId, 'status' => $status, 'mark' => 1, 'update_time' => time()]);
+            RedisService::clear("caches:members:cartList:{$userId}");
+            $count = $this->getCartCount($userId, true);
+            return ['id' => $cartId, 'count' => $count];
+        } else {
+            $cartId = CartsModel::insertGetId(['user_id' => $userId, 'goods_id' => $goodsId, 'merch_id' => $merchId, 'sku_id' => $skuId, 'num' => $num, 'status' => $status, 'mark' => 1, 'create_time' => time()]);
+            RedisService::clear("caches:members:cartList:{$userId}");
+            $count = $this->getCartCount($userId, true);
+            return ['id' => $cartId, 'count' => $count];
+        }
+    }
+
+    /**
+     * 删除购物车商品
+     * @param $userId
+     * @param $params
+     * @return bool
+     */
+    public function deleteCart($userId, $params)
+    {
+        $ids = isset($params['ids']) ? $params['ids'] : [];
+        if (empty($ids)) {
+            $this->error = 2923;
+            return false;
+        }
+
+        CartsModel::whereIn('id', $ids)->update(['status' => 2, 'update_time' => time()]);
+        $this->error = 1002;
+        RedisService::clear("caches:members:cartCount:{$userId}");
+        RedisService::clear("caches:members:cartList:{$userId}");
+        return true;
+    }
+
+    /**
+     * 购物车列表
+     * @param $userId
+     * @param int $pageSize
+     * @return array|\Illuminate\Database\Eloquent\Builder[]|\Illuminate\Database\Eloquent\Collection|mixed
+     */
+    public function getCartList($userId, $pageSize = 30)
+    {
+        $cacheKey      = "caches:members:cartList:{$userId}";
+        $cacheCountKey = "caches:members:cartCount:{$userId}";
+        $datas         = RedisService::get($cacheKey);
+        if ($datas) {
+            return $datas;
+        }
+
+        $datas = CartsModel::with(['sku'])->from('carts as a')
+            ->leftJoin('goods as b', 'b.goods_id', '=', 'a.goods_id')
+            ->leftJoin('goods_sku as c', 'c.sku_id', '=', 'a.sku_id')
+            ->where(['a.status' => 1, 'a.mark' => 1, 'b.status' => 1, 'b.mark' => 1])
+            ->where('b.cost_price', '>', 0)
+            ->where('a.num', '>', 0)
+            ->where('a.user_id', '=', $userId)
+            ->select(['a.id as cart_id', 'b.goods_id', 'b.merch_id', 'b.goods_name', 'b.supply_type', 'b.main_img', 'b.cost_price', 'b.retail_price', 'b.limit_num', 'b.lowest_num', 'b.brand_name', 'a.num', 'a.sku_id'])
+            ->orderBy('a.create_time', 'desc')
+            ->limit($pageSize)
+            ->get();
+        $datas = $datas ? $datas->toArray() : [];
+        if ($datas) {
+
+            // 价格等参数格式化
+            $locale     = RedisService::get("caches:locale:lang_{$userId}");
+            $locale     = $locale ? $locale : session('locale_lang');
+            $locale     = $locale ? $locale : 'zh-cn';
+            $supplyList = config('goods.supplyList');
+
+            $usdtPrice = RedisService::get("caches:wallets:usdt_rate");
+            if ($usdtPrice <= 0) {
+                $usdtCnyPrice = ConfigService::make()->getConfigByCode('usdt_cny_price', 7.2);
+                $usdtPrice    = $usdtCnyPrice > 0 && $usdtCnyPrice < 100 ? $usdtCnyPrice : 0;
+            }
+            $xdPrice = ConfigService::make()->getConfigByCode('xd_price', 100);
+            $xdPrice = $xdPrice > 0 && $xdPrice <= 10000 ? $xdPrice : 100;
+
+            foreach ($datas as &$item) {
+                $item['detail_img']    = isset($item['detail_img']) && $item['detail_img'] ? json_decode($item['detail_img'], true) : [];
+                $item['supply_name']   = isset($supplyList[$item['supply_type']]) ? $supplyList[$item['supply_type']] : '';
+                $item['usdt_price']    = $usdtPrice;
+                $item['xd_price_rate'] = $xdPrice;
+                $item['retail_price1'] = $item['retail_price'];
+                $skuInfo               = isset($item['sku']) ? $item['sku'] : [];
+                $skuInfo['attr']       = isset($skuInfo['attr']) && $skuInfo['attr'] ? json_decode($skuInfo['attr'], true) : [];
+                $item['sku']           = $skuInfo;
+                $price                 = isset($skuInfo['plat_price']) ? $skuInfo['plat_price'] : 0;
+                if ($price) {
+                    $item['retail_price'] = $this->getRealSalePrice($price);
+                } else {
+                    $item['retail_price'] = $this->getRealSalePrice($item['cost_price']);
+                }
+            }
+            unset($item);
+
+            RedisService::set($cacheCountKey, count($datas), rand(300, 600));
+            RedisService::set($cacheKey, $datas, rand(300, 600));
+        }
+
+
+        return $datas;
+    }
+
+    /**
+     * 购物车中数量
+     * @param $userId
+     * @return array|mixed
+     */
+    public function getCartCount($userId, $refresh = false)
+    {
+        $cacheKey = "caches:member:cartCount:{$userId}";
+        $data     = RedisService::get($cacheKey);
+        if ($data > 0 && !$refresh) {
+            return $data;
+        }
+
+        $data = CartsModel::from('carts as a')
+            ->leftJoin('goods as b', 'b.goods_id', '=', 'a.goods_id')
+            ->where(['a.status' => 1, 'a.mark' => 1, 'b.status' => 1, 'b.mark' => 1])
+            ->where('a.num', '>', 0)
+            ->where('b.cost_price', '>', 0)
+            ->where('a.user_id',$userId)
+            ->count('a.id');
+        if ($data) {
+            RedisService::set($cacheKey, $data, rand(300, 600));
+        }
+
+        return $data;
+    }
+
+    /**
+     * 运费
+     */
+    public function getFreight($userId, $addressId, $skuList)
+    {
+        $cacheKey = "caches:goods:freight:{$userId}_{$addressId}_" . md5(json_encode($skuList, 256));
+        $data     = RedisService::get($cacheKey);
+        if ($data) {
+            return $data;
+        }
+
+        if (empty($addressId)) {
+            $address    = MemberAddressService::make()->getBindInfo($userId);
+            $streetCode = isset($address['street_code']) ? $address['street_code'] : '';
+            $addressId  = $streetCode ? $streetCode : (isset($address['district_code']) ? $address['district_code'] : '');
+        }
+
+        $result  = SupplyService::make()->getApiData('getFreight', ['address_id' => intval($addressId), 'sku_list' => $skuList]);
+        $freight = isset($result['freight']) ? floatval($result['freight']) : -1;
+        if ($freight >= 0) {
+            // 价格参数
+            $usdtPrice = RedisService::get("caches:wallets:usdt_rate");
+            if ($usdtPrice <= 0) {
+                $usdtCnyPrice = ConfigService::make()->getConfigByCode('usdt_cny_price', 7.2);
+                $usdtPrice    = $usdtCnyPrice > 0 && $usdtCnyPrice < 100 ? $usdtCnyPrice : 0;
+            }
+            $xdPrice = ConfigService::make()->getConfigByCode('xd_price', 100);
+            $xdPrice = $xdPrice > 0 && $xdPrice <= 10000 ? $xdPrice : 100;
+
+            $xdFreight = $freight ? moneyFormat($freight / $usdtPrice * $xdPrice, 2) : 0;
+            RedisService::set($cacheKey, ['freight' => $xdFreight, 'fee' => $freight], rand(5, 10));
+            return ['freight' => $xdFreight, 'fee' => $freight];
+        } else {
+            $errorCode   = SupplyService::make()->getError();
+            $this->error = $errorCode ? $errorCode : 1052;
+            return false;
+        }
+    }
+
+    public function getSkuInfo($sakuId)
+    {
+        $cacheKey = "caches:goodsSku:{$sakuId}";
+        $data     = RedisService::get($cacheKey);
+        if ($data) {
+            return $data;
+        }
+
+        $data = GoodsSkuModel::where(['sku_id' => $sakuId, 'status' => 1, 'mark' => 1])
+            ->select(['id', 'sku_id', 'goods_id', 'retail_price', 'plat_price', 'sku_sn', 'sku_name', 'main_img', 'attr'])
+            ->first();
+        $data = $data ? $data->toArray() : [];
+        if ($data) {
+            RedisService::set($cacheKey, $data, rand(3, 5));
+        }
+
+        return $data;
+    }
+
+    /**
+     * 更新浏览量
+     * @param $userId
+     * @param $dynamicId
+     * @return array|mixed
+     */
+    public function updateView($userId, $id)
+    {
+        $cacheKey = "caches:goods:views:u{$userId}_d{$id}";
+        $data     = RedisService::get($cacheKey);
+        if ($data) {
+            return false;
+        }
+
+        $data = $this->model->where(['goods_id' => $id])->update(['views' => DB::raw('views + 1'), 'update_time' => time()]);
+        RedisService::set($cacheKey, $id, rand(1, 3) * 7200);
+        return $data;
+    }
+
+    /**
+     * 更新商品SKU数据到本地
+     * @param int $pageSize
+     * @param $params 参数
+     * @return array|false
+     */
+    public function updateGoodsSku($pageSize = 100, $params = [])
+    {
+        $cacheKey = "caches:supply:goods_sku_update_{$pageSize}";
+        if (RedisService::get($cacheKey)) {
+            $this->error = 1047;
+            return false;
+        }
+
+        $page     = RedisService::get($cacheKey . '_page');
+        $page     = $page ? $page + 1 : 1;
+        $lastDate = GoodsSkuModel::where(['mark' => 1])->orderBy('last_update_at', 'desc')->value('last_update_at');
+        $params   = [
+            'limit' => $pageSize > 0 ? $pageSize : 50,
+            'page'  => $page,
+            'date'  => $lastDate ? $lastDate : '',  // 开始时间
+        ];
+        $goods    = [];
+        $updated  = 0;
+        $error    = 0;
+        $datas    = SupplyService::make()->getApiData('getSkuUpdate', $params);
+        if ($datas && $datas['list']) {
+            foreach ($datas['list'] as &$item) {
+                $goodsId    = isset($item['goods_id']) ? $item['goods_id'] : 0;
+                $goodsSkuSn = isset($item['sku_sn']) ? $item['sku_sn'] : '';
+                $changeType = isset($item['change_type']) ? $item['change_type'] : '';
+                if ($goodsId && $goodsSkuSn && $changeType) {
+
+                    $skuInfo = SupplyService::make()->getApiData('getSkuDetail', ['sku_sn' => $goodsSkuSn]);
+                    if ($skuInfo) {
+                        $updateData = ['goods_id' => $goodsId, 'sku_sn' => $goodsSkuSn, 'remark' => 'SKU更新', 'update_time' => time(), 'mark' => 1, 'last_update_at' => $item['update_time']];
+                        if (isset($skuInfo['sku_name']) && $skuInfo['sku_name']) {
+                            $updateData['sku_name'] = $skuInfo['sku_name'];
+                        }
+                        if (isset($skuInfo['main_img']) && $skuInfo['main_img']) {
+                            $updateData['main_img'] = $skuInfo['main_img'];
+                        }
+                        if (isset($skuInfo['spu_sn']) && $skuInfo['spu_sn']) {
+                            $updateData['spu_sn'] = $skuInfo['spu_sn'];
+                        }
+                        if (isset($skuInfo['sku_id']) && $skuInfo['sku_id']) {
+                            $updateData['sku_id'] = intval($skuInfo['sku_id']);
+                        }
+
+                        if (isset($skuInfo['status']) && $skuInfo['status']) {
+                            $updateData['status'] = intval($skuInfo['status']);
+                        }
+                        if (isset($skuInfo['retail_price']) && $skuInfo['retail_price']) {
+                            $updateData['retail_price'] = floatval($skuInfo['retail_price']);
+                        }
+                        if (isset($skuInfo['plat_price']) && $skuInfo['plat_price']) {
+                            $updateData['plat_price'] = floatval($skuInfo['plat_price']);
+                        }
+                        if (isset($skuInfo['detail_img']) && $skuInfo['detail_img']) {
+                            $updateData['detail_img'] = json_encode($skuInfo['detail_img'], 256);
+                        }
+                        if (isset($skuInfo['attr']) && $skuInfo['attr']) {
+                            $updateData['attr'] = json_encode($skuInfo['attr'], 256);
+                        }
+
+                        if(isset($skuInfo['status'])){
+                            $updateGoodsData = ['update_time'=>time()];
+                            // 下架
+                            if($skuInfo['status'] == 0){
+                                $updateGoodsData['status'] = 0;
+                            }
+                            // 删除
+                            else if(in_array(intval($skuInfo['status']),[2,3])){
+                                $updateGoodsData['status'] = 3;
+                                $updateGoodsData['mark'] = 0;
+                            }else if($skuInfo['status'] == 1){
+                                $updateGoodsData['status'] = 1;
+                            }
+
+                            // 更新商品状态
+                            GoodsModel::where(['goods_id' => $goodsId])->update($updateGoodsData);
+                        }
+
+                        // 更新商品SKU信息
+                        if (GoodsSkuModel::where(['goods_id' => $goodsId])->value('id')) {
+                            GoodsSkuModel::where(['goods_id' => $goodsId, 'mark' => 1])->update($updateData);
+                            $updated++;
+                        } else {
+                            $error++;
+                        }
+
+                    } else {
+                        $error++;
+                    }
+                } else {
+                    $error++;
+                }
+            }
+            unset($item);
+            RedisService::set($cacheKey . '_page', $page, rand(300, 600));
+        } else {
+            RedisService::set($cacheKey . '_page', 0, rand(300, 600));
+        }
+
+        return ['count' => count($goods), 'updated' => $updated, 'errorCount' => $error, 'page' => $page];
+    }
+
+    /**
+     * 更新商品
+     * @param int $pageSize
+     * @param $params 参数
+     * @return array|false
+     */
+    public function updateGoods($pageSize = 0, $params = [])
+    {
+        set_time_limit(0);
+        $cateId = isset($params['cate_id']) ? $params['cate_id'] : 0;
+        $cacheKey = "caches:supply:goods_list_update_{$pageSize}_{$cateId}";
+        if (RedisService::get($cacheKey)) {
+            $this->error = 1047;
+            return false;
+        }
+
+        $size     = ConfigService::make()->getConfigByCode('goods_update_limit', 0);
+        $pageSize = $pageSize? $pageSize : ($size > 10 && $size <= 5000 ? $size : 500);
+        $page     = RedisService::get($cacheKey . '_page');
+        $page     = $page ? $page + 1 : 1;
+//        $lastTime = $this->model->where(['mark' => 1])->orderBy('create_time', 'desc')->value('create_time');
+//        $lastTime = $lastTime? date('Y-m-d H:i:s', strtotime($lastTime)) : '';
+//        $lastTime = date('Y-m-d H:i:s', time() - 60 * 86400);
+        $lastTime = '';
+        $params   = [
+            'limit'       => $pageSize > 0 ? $pageSize : 50,
+            'page'        => $page,
+            'status'      => isset($params['status']) ? $params['status'] : 1, // 状态:0-全部,1-上架的,2-下架的
+            'supply_type' => isset($params['supply_type']) ? $params['supply_type'] : 0,  // 渠道商
+            'title'       => isset($params['title']) ? $params['title'] : '',  // 标题关键词
+            'cate_id'     => isset($params['cate_id']) ? $params['cate_id'] : '',  // 分类ID
+            'begin_time'  => $lastTime ? $lastTime : '',  // 开始时间
+        ];
+        $goods    = [];
+        $skus     = [];
+        $updated  = 0;
+        $error    = 0;
+        $infoError = 0;
+        $datas    = SupplyService::make()->getApiData('getGoodsList', $params);
+        if ($datas && $datas['list']) {
+            foreach ($datas['list'] as &$item) {
+                $goodsId = isset($item['goods_id']) ? $item['goods_id'] : 0;
+                if ($goodsId && !$this->checkGoods($goodsId)) {
+
+                    $info = $this->getApiInfo($goodsId);
+                    if ($info) {
+                        $skuList = isset($info['sku_list']) ? $info['sku_list'] : [];
+                        $goods[] = [
+                            'goods_id'       => $goodsId,
+                            'supply_type'    => isset($item['supply_type']) ? $item['supply_type'] : 0,
+                            'spu_sn'         => isset($item['spu_sn']) ? $item['spu_sn'] : '',
+                            'spu_name'       => isset($info['spu_name']) ? $info['spu_name'] : '',
+                            'main_img'       => isset($info['main_img']) ? $info['main_img'] : '',
+                            'detail_img'     => isset($info['detail_img']) ? json_encode($info['detail_img'], 256) : '',
+                            'goods_name'     => isset($item['goods_name']) ? $item['goods_name'] : '',
+                            'brand_name'     => isset($info['brand_name']) ? $info['brand_name'] : '',
+                            'limit_num'      => isset($info['limit_num']) ? intval($info['limit_num']) : 0,
+                            'lowest_num'     => isset($info['lowest_num']) ? intval($info['lowest_num']) : 1,
+                            'cost_price'     => isset($info['cost_price']) ? floatval($info['cost_price']) : 0,
+                            'retail_price'   => isset($info['retail_price']) ? floatval($info['retail_price']) : 0,
+                            'profit'         => isset($info['profit']) ? floatval($info['profit']) : 0,
+                            'sku_list'       => $skuList ? json_encode($skuList, 256) : '',
+                            'sku_total'      => isset($info['sku_total']) ? intval($info['sku_total']) : 0,
+                            'tag'            => isset($item['tag']) ? json_encode($item['tag'], 256) : '',
+                            'status'         => isset($info['status']) ? intval($info['status']) : 1,
+                            'cate_id'        => isset($item['cate_id']) ? intval($item['cate_id']) : 0,
+                            'last_update_at' => isset($info['update_time']) ? $info['update_time'] : (isset($item['time']) && $item['time'] ? $item['time'] : date('Y-m-d H:i:s')),
+                            'create_time'    => time(),
+                        ];
+
+                        foreach ($skuList as $v) {
+                            $skus[] = [
+                                'sku_id'         => isset($v['sku_id']) ? $v['sku_id'] : 0,
+                                'goods_id'       => $goodsId,
+                                'spu_sn'         => isset($v['spu_sn']) ? $v['spu_sn'] : '',
+                                'sku_sn'         => isset($v['sku_sn']) ? $v['sku_sn'] : '',
+                                'sku_name'       => isset($v['sku_name']) ? $v['sku_name'] : '',
+                                'main_img'       => isset($v['main_img']) ? $v['main_img'] : '',
+                                'status'         => isset($v['status']) ? $v['status'] : 1,
+                                'source_type'    => isset($v['source_type']) ? $v['source_type'] : 0,
+                                'retail_price'   => isset($v['retail_price']) ? floatval($v['retail_price']) : 0,
+                                'plat_price'     => isset($v['plat_price']) ? floatval($v['plat_price']) : 0,
+                                'profit'         => isset($v['profit']) ? floatval($v['profit']) : 0,
+                                'last_update_at' => isset($v['update_time']) ? $v['update_time'] : date('Y-m-d H:i:s'),
+                                'detail_img'     => isset($v['detail_img']) ? json_encode($v['detail_img'], 256) : '',
+                                'attr'           => isset($v['attr']) ? json_encode($v['attr'], 256) : '',
+                                'remark'         => 'SKU同步创建',
+                            ];
+                        }
+
+                        $updated++;
+                    } else {
+                        $infoError++;
+                    }
+
+                } else {
+                    $error++;
+                }
+            }
+            unset($item);
+        } else {
+            RedisService::set($cacheKey . '_page', 0, rand(300, 600));
+        }
+
+        if ($goods) {
+            RedisService::set($cacheKey . '_page', $page, rand(300, 600));
+            RedisService::set($cacheKey, $goods, rand(5, 10));
+            DB::beginTransaction();
+            try {
+                $this->model->insertAll($goods);
+                if ($skus) {
+                    GoodsSkuModel::insert($skus);
+                }
+
+                DB::commit();
+            } catch (\Exception $exception) {
+                RedisService::clear($cacheKey);
+                DB::rollBack();
+            }
+
+        }
+
+
+        return ['total'=>isset($datas['list'])? count($datas['list']) : 0,'all'=>isset($datas['total'])?$datas['total']:0,'count' => count($goods), 'updated' => $updated, 'errorCount' => $error,'info_error'=>$infoError, 'page' => $page];
+    }
+
+    /**
+     * 更新商品分类
+     * @param int $pid 上级ID
+     * @param int $pageSize
+     * @param $params 参数
+     * @return array|false
+     */
+    public function updateGoodsCategory($pid = 0, $pageSize = 200, $params = [])
+    {
+        set_time_limit(0);
+        $cacheKey = "caches:supply:goods_category_update_{$pid}_{$pageSize}";
+        if (RedisService::get($cacheKey)) {
+            $this->error = 1047;
+            return false;
+        }
+
+        $params    = [
+            'limit' => $pageSize > 0 ? $pageSize : 50,
+            'page'  => 1,
+            'pid'   => $pid, // 上级ID
+        ];
+        $categorys = [];
+        $updated   = 0;
+        $error     = 0;
+        $datas     = SupplyService::make()->getApiData('getGoodsCategory', $params);
+        if ($datas && $datas['data']) {
+            foreach ($datas['data'] as &$item) {
+                $cateId = isset($item['id']) ? $item['id'] : 0;
+                if ($cateId && !$this->checkCategory($cateId)) {
+                    $categorys[] = [
+                        'cate_id'     => $cateId,
+                        'name'        => isset($item['name']) ? $item['name'] : '',
+                        'pid'         => isset($item['pid']) ? intval($item['pid']) : 0,
+                        'create_time' => time(),
+                    ];
+                    $updated++;
+                } else {
+                    $error++;
+                }
+            }
+            unset($item);
+        }
+
+        if ($categorys) {
+            RedisService::set($cacheKey, $categorys, rand(5, 10));
+            GoodsCategoryModel::insert($categorys);
+        }
+
+
+        return ['count' => count($categorys), 'updated' => $updated, 'pid' => $pid, 'errorCount' => $error];
+    }
+
+    /**
+     * 验证
+     * @param $goodsId
+     * @return bool
+     */
+    public function checkGoods($goodsId)
+    {
+        $cacheKey = "caches:goods:check_{$goodsId}";
+        if (RedisService::get($cacheKey) || RedisService::exists($cacheKey)) {
+            return true;
+        }
+
+        $data = $this->model->where(['goods_id' => $goodsId, 'mark' => 1])->value('id');
+        RedisService::set($cacheKey, $data, rand(30, 60));
+        return $data;
+    }
+
+    /**
+     * 验证分类
+     * @param $cateId
+     * @return bool
+     */
+    public function checkCategory($cateId)
+    {
+        $cacheKey = "caches:goods:category_check_{$cateId}";
+        if (RedisService::get($cacheKey) || RedisService::exists($cacheKey)) {
+            return true;
+        }
+
+        $data = GoodsCategoryModel::where(['cate_id' => $cateId, 'mark' => 1])->value('id');
+        RedisService::set($cacheKey, $data, rand(30, 60));
+        return $data;
+    }
+
+    /**
+     * 接口商品详情
+     * @param $goodsId 商品ID
+     * @param int $isReal 是否实时数据,0-是,1-否
+     * @param int $type 数据类型:0-详情,1-仅SKU数据
+     * @return array|false|mixed|string
+     */
+    public function getApiInfo($goodsId, $isReal = 0, $type = 0)
+    {
+        $cacheKey = "caches:goods:detail_{$goodsId}_{$isReal}_{$type}";
+        $info     = RedisService::get($cacheKey);
+        if (empty($info)) {
+            $params = [
+                'goods_id' => $goodsId,
+                'is_real'  => $isReal,
+                'type'     => $type
+            ];
+            $info   = SupplyService::make()->getApiData('getGoodsDetail', $params);
+            if ($info) {
+                RedisService::set($cacheKey, $info, rand(5, 10));
+            }
+        }
+        return $info;
+    }
+
+    /**
+     * 购物车商品数量
+     * @param $userId
+     * @param $params
+     * @return bool
+     */
+    public function count($userId, $params)
+    {
+        $count = CartsModel::where(['user_id' => $userId,'status'=>1,'mark'=>1])->count();
+        return ['count' => $count];
+    }
+
+}

+ 497 - 0
app/Services/Api/MemberService.php

@@ -0,0 +1,497 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Services\Api;
+
+use App\Helpers\Jwt;
+use App\Models\DossierModel;
+use App\Models\MemberModel;
+use App\Services\BaseService;
+use App\Services\Common\CityService;
+use App\Services\ConfigService;
+use App\Services\EmailService;
+use App\Services\RedisService;
+use App\Services\SmsService;
+use App\Services\ToolService;
+use Illuminate\Support\Facades\DB;
+use phpqrcode\QRcode;
+
+/**
+ * 会员管理-服务类
+ * @author laravel开发员
+ * @since 2020/11/11
+ * Class MemberService
+ * @package App\Services\Api
+ */
+class MemberService extends BaseService
+{
+    public static $instance = null;
+
+    /**
+     * 构造函数
+     * @since 2020/11/11
+     * MemberService constructor.
+     */
+    public function __construct()
+    {
+        $this->model = new MemberModel();
+    }
+
+    /**
+     * @return static|null
+     */
+    public static function make()
+    {
+        if (!self::$instance) {
+            self::$instance = new static();
+        }
+
+        return self::$instance;
+    }
+
+    /**
+     * 用户登录
+     * @param $params
+     * @return array|false
+     */
+    public function login($params)
+    {
+        // 授权
+        $account = isset($params['account']) ? $params['account'] : '';
+        $smsCode = isset($params['sms_code']) ? $params['sms_code'] : ''; // 短信验证码或邮箱验证码
+        $type = isset($params['type']) ? $params['type'] : 1;
+        $password = isset($params['password']) ? $params['password'] : '';
+        $appSources = isset($params['app_sources']) ? $params['app_sources'] : '';
+        $incode = isset($params['incode']) ? $params['incode'] : '';
+        if (empty($params) || empty($account)) {
+            $this->error = 2014;
+            return false;
+        }
+
+        $userInfo = $this->model->where(['mark' => 1])
+            ->where(function ($query) use ($account, $type) {
+                if ($type == 1 || $type == 2) {
+                    $query->where(['username' => $account])->orWhere(['mobile' => $account])->orWhere(['email' => $account]);
+                } else if ($type == 3) {
+                    $query->orWhere(['email' => $account]);
+                }
+            })
+            ->select(['id', 'openid', 'username', 'email', 'mobile', 'password', 'parent_id', 'vip', 'code', 'status', 'mark'])
+            ->first();
+        $userInfo = $userInfo ? $userInfo->toArray() : [];
+        $userId = isset($userInfo['id']) ? $userInfo['id'] : 0;
+        $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
+
+        if ($userInfo && $status != 1) {
+            $this->error = '账号已被冻结,请联系客服';
+            return false;
+        }
+
+        // 账号密码
+        if ($type == 1) {
+            // 未注册
+            if (empty($userInfo)) {
+                $this->error = '账号未注册,请选择其他方式登录注册';
+                return false;
+            }
+
+            // 已注册验证密码
+            $userPassword = isset($userInfo['password']) ? $userInfo['password'] : '';
+            if ($userInfo && $userPassword != get_password($password)) {
+                $this->error = '登录密码错误';
+                return false;
+            }
+        } else if ($type == 2) {
+            // 验证短信验证码
+            if (!SmsService::make()->check($account, $smsCode, 'login')) {
+                $this->error = SmsService::make()->getError();
+                return false;
+            }
+        } else if ($type == 3) {
+            // 已注册验证邮箱验证码
+            if (!EmailService::make()->check($account, $smsCode, 'login')) {
+                $this->error = EmailService::make()->getError();
+                return false;
+            }
+        }
+
+        // 未注册
+        $ip = get_client_ip();
+        $system = isset($params['system']) ? $params['system'] : [];
+        if (empty($userInfo)) {
+            // 推荐人
+            $parentId = 0;
+            $parents = '';
+            if ($incode) {
+                $inviteInfo = $this->model->where(['code' => $incode, 'mark' => 1])
+                    ->select(['id', 'parents', 'parent_id'])
+                    ->first();
+                $parentId = isset($inviteInfo['id']) ? $inviteInfo['id'] : 0;
+                $parents = isset($inviteInfo['parents']) ? $parentId . ',' . $inviteInfo['parents'] : ($parentId ? $parentId . ',' : '');
+                if(empty($parentId)){
+                    $this->error = '邀请码错误';
+                    return false;
+                }
+            }
+
+            // 账号注册
+            DB::beginTransaction();
+            $userId = $this->model->max('id') + 1;
+            $userInfo = [
+                'username' => $type == 1 ? $account : '',
+                'mobile' => $type == 2 ? $account : '',
+                'email' => $type == 3 ? $account : '',
+                'nickname' => get_nickname('T'),
+                'password' => $type == 1 ? get_password($password) : '',
+                'member_level' => 0,
+                'parent_id' => $parentId,
+                'parents' => $parents,
+                'app_uuid' => isset($system['uuid']) ? $system['uuid'] : '',
+                'device' => $appSources == 'android' ? 2 : 1,
+                'source' => 1,
+                'status' => 1,
+                'login_ip' => $ip,
+                'code' => strtoupper(get_random_code(9, 'X', "{$userId}")),
+                'create_time' => time(),
+                'login_time' => time(),
+                'mark' => 1
+            ];
+            if (!$this->model->insert($userInfo)) {
+                DB::rollBack();
+                $this->error = EmailService::make()->getError();
+                return false;
+            }
+
+            // 资料
+            $ipData = ToolService::make()->getIpAddress($ip, '');
+            $province = isset($ipData['regionName']) ? $ipData['regionName'] : '';
+            $city = isset($ipData['city']) ? $ipData['city'] : '';
+            $provinceId = CityService::make()->getFieldByName($province);
+            $cityId = CityService::make()->getFieldByName($city);
+            $birthday = date('Y-m-d');
+            $starData = getStar($birthday);
+            $dossier = [
+                'user_id'=> $userId,
+                'nickname'=> '自己',
+                'type'=>1,
+                'birthday'=> $birthday,
+                'province_id' => $provinceId,
+                'city_id' => $cityId,
+                'city' => $city,
+                'star'=> isset($starData['code'])? $starData['code'] : '',
+                'star_text'=> isset($starData['name'])? $starData['name'] : '',
+                'status'=>1,
+                'is_default'=>1,
+            ];
+
+            if (!DossierModel::insert($dossier)) {
+                DB::rollBack();
+                $this->error = EmailService::make()->getError();
+                return false;
+            }
+
+            // TODO 邀请注册奖励
+
+            DB::commit();
+            unset($userInfo['password']);
+            unset($userInfo['parents']);
+            unset($userInfo['parents']);
+        } else {
+            $this->model->where(['id' => $userId])->update([
+                'app_uuid' => isset($system['uuid']) ? $system['uuid'] : '',
+                'login_ip' => $ip,
+                'update_time' => time(),
+                'login_time' => time(),
+            ]);
+        }
+
+        // 获取登录授权token
+        $jwt = new Jwt('jwt_star_app');
+        $token = $jwt->getToken($userId);
+
+        // 结果返回
+        $result = [
+            'access_token' => $token,
+            'info' => ['uid' => $userId, 'parent_id' => $userInfo['parent_id'], 'account' => $account, 'code' => $userInfo['code']],
+        ];
+        $this->error = 2004;
+        RedisService::set("auths:info:{$userId}", $userInfo, 2 * 24 * 3600);
+        return $result;
+    }
+
+    /**
+     * 邀请注册
+     * @param $params
+     * @return array|false
+     */
+    public function register($params)
+    {
+        // 授权
+        $account = isset($params['account']) ? $params['account'] : '';
+        $smsCode = isset($params['sms_code']) ? $params['sms_code'] : ''; // 短信验证码或邮箱验证码
+        $type = isset($params['type']) ? $params['type'] : 1;
+        $password = isset($params['password']) ? $params['password'] : '';
+        $appSources = isset($params['app_sources']) ? $params['app_sources'] : '';
+        $incode = isset($params['incode']) ? $params['incode'] : '';
+        if (empty($params) || empty($account) || empty($incode)) {
+            $this->error = 2014;
+            return false;
+        }
+
+        $userInfo = $this->model->where(['mark' => 1])
+            ->where(function ($query) use ($account, $type) {
+                if ($type == 1 || $type == 2) {
+                    $query->where(['username' => $account])->orWhere(['mobile' => $account])->orWhere(['email' => $account]);
+                } else if ($type == 3) {
+                    $query->orWhere(['email' => $account]);
+                }
+            })
+            ->select(['id', 'openid', 'username', 'email', 'mobile', 'password', 'parent_id', 'vip', 'code', 'status', 'mark'])
+            ->first();
+        $userInfo = $userInfo ? $userInfo->toArray() : [];
+        if ($userInfo) {
+            $this->error = '账号已注册,请直接下载APP或到小程序内登录使用';
+            return false;
+        }
+
+        // 账号密码
+        if ($type == 2) {
+            // 已注册验证短信验证码
+            if (!SmsService::make()->check($account, $smsCode, 'reg')) {
+                $this->error = SmsService::make()->getError();
+                return false;
+            }
+        } else if ($type == 3) {
+            // 已注册验证邮箱验证码
+            if (!EmailService::make()->check($account, $smsCode, 'reg')) {
+                $this->error = EmailService::make()->getError();
+                return false;
+            }
+        }
+
+        // 推荐人
+        $parentId = 0;
+        $parents = '';
+        if ($incode) {
+            $inviteInfo = $this->model->where(['code' => $incode, 'mark' => 1])
+                ->select(['id', 'parents', 'parent_id'])
+                ->first();
+            $parentId = isset($inviteInfo['id']) ? $inviteInfo['id'] : 0;
+            $parents = isset($inviteInfo['parents']) ? $parentId . ',' . $inviteInfo['parents'] : ($parentId ? $parentId . ',' : '');
+        }
+
+        if(empty($parentId)){
+            $this->error = '邀请码错误';
+            return false;
+        }
+
+        // 未注册
+        $ip = get_client_ip();
+        $ipData = ToolService::make()->getIpAddress($ip, '');
+        $province = isset($ipData['regionName']) ? $ipData['regionName'] : '';
+        $city = isset($ipData['city']) ? $ipData['city'] : '';
+        $provinceId = CityService::make()->getFieldByName($province);
+        $cityId = CityService::make()->getFieldByName($city);
+        $system = isset($params['system']) ? $params['system'] : [];
+
+        // 账号注册
+        DB::beginTransaction();
+        $userId = $this->model->max('id') + 1;
+        $userInfo = [
+            'username' => $type == 1 ? $account : '',
+            'mobile' => $type == 2 ? $account : '',
+            'email' => $type == 3 ? $account : '',
+            'nickname' => get_nickname('T'),
+            'password' => $type == 1 ? get_password($password) : '',
+            'member_level' => 0,
+            'parent_id' => $parentId,
+            'parents' => $parents,
+            'app_uuid' => isset($system['uuid']) ? $system['uuid'] : '',
+            'device' => $appSources == 'android' ? 2 : 1,
+            'source' => 1,
+            'status' => 1,
+            'login_ip' => $ip,
+            'code' => strtoupper(get_random_code(9, 'X', "{$userId}")),
+            'create_time' => time(),
+            'login_time' => time(),
+            'mark' => 1
+        ];
+        if (!$this->model->insert($userInfo)) {
+            DB::rollBack();
+            $this->error = EmailService::make()->getError();
+            return false;
+        }
+
+        // 资料
+        $birthday = date('Y-m-d');
+        $starData = getStar($birthday);
+        $dossier = [
+            'user_id'=> $userId,
+            'nickname'=> '自己',
+            'type'=>1,
+            'birthday'=> $birthday,
+            'star'=> isset($starData['code'])? $starData['code'] : '',
+            'star_text'=> isset($starData['name'])? $starData['name'] : '',
+            'province_id' => $provinceId,
+            'city_id' => $cityId,
+            'city' => $city,
+            'status'=>1,
+            'is_default'=>1,
+        ];
+
+        if (!DossierModel::insert($dossier)) {
+            DB::rollBack();
+            $this->error = EmailService::make()->getError();
+            return false;
+        }
+
+        // TODO 邀请注册奖励
+
+        DB::commit();
+        unset($userInfo['password']);
+        unset($userInfo['parents']);
+        unset($userInfo['parents']);
+
+        // 结果返回
+        $siteInfo = ConfigService::make()->getConfigByGroup(1);
+        $result = [
+            'app_urls'=>[
+                'android'=> isset($siteInfo['android_app_url']['value'])? $siteInfo['android_app_url']['value'] : '',
+                'ios'=> isset($siteInfo['ios_app_url']['value'])? $siteInfo['ios_app_url']['value'] : '',
+            ],
+            'info' => ['uid' => $userId, 'parent_id' => $userInfo['parent_id'], 'account' => $account, 'code' => $userInfo['code']],
+        ];
+        $this->error = 2004;
+        RedisService::set("auths:info:{$userId}", $userInfo, 2 * 24 * 3600);
+        return $result;
+    }
+
+
+    /**
+     * 用户信息
+     * @param int $userId 用户ID
+     * @param false $refresh
+     * @return array|mixed
+     */
+    public function getInfo(int $userId, $refresh = false)
+    {
+        $cacheKey = "caches:member:info_{$userId}";
+        $info = RedisService::get($cacheKey);
+        if ($info && !$refresh) {
+            return $info;
+        }
+
+        $info = $this->model->with(['parent','profile'])
+            ->where(['id' => $userId, 'mark' => 1])
+            ->select(['id', 'nickname', 'avatar', 'code', 'member_level', 'beans', 'vip', 'profit', 'balance', 'view_ads', 'ads_beans', 'mobile', 'parent_id', 'email', 'username', 'status'])
+            ->first();
+        $info = $info ? $info->toArray() : [];
+        if (empty($info)) {
+            $this->error = 2016;
+            return false;
+        }
+
+        $profile = isset($info['profile'])? $info['profile'] : [];
+        if ($info['avatar']) {
+            $info['avatar'] = get_image_url($info['avatar']);
+        } else {
+            $star = isset($profile['star']) && $profile['star'] ? $profile['star'] : '';
+            $gender = isset($profile['gender']) && $profile['gender'] ? $profile['gender'] : 0;
+            $name = intval($info['id'] % 3) + 1;
+            if ($star && $gender) {
+                $name = "{$star}/" . ($gender == 1 ? 'f_' : 'm_') . $name;
+            }
+            $avatar = "/images/avatar/{$name}.jpeg";
+            $info['avatar'] = get_image_url($avatar);
+        }
+
+        $info['birthday'] = isset($profile['birthday']) && $profile['birthday']? $profile['birthday'] : date('Y-m-d');
+        $info['star'] = isset($profile['star']) && $profile['star']? $profile['star'] : '';
+        $info['star_text'] = isset($profile['star_text']) && $profile['star_text']? $profile['star_text'] : '';
+        if(empty($info['star'])){
+            $starData = getStar($info['birthday']);
+            $info['star'] = isset($starData['code']) ? $starData['code'] : '';
+            $info['star_text'] = isset($starData['name']) ? $starData['name'] : '';
+        }
+
+        $info['share_url'] = env('WEB_URL').'#/pages/share/index?incode='.$info['code'];
+        $info['share_qrcode'] = get_image_url($this->makeQrcode($info['share_url']));
+
+
+        $info['orders'] = [
+
+        ];
+
+        RedisService::set($cacheKey, $info, rand(3, 5));
+        return $info;
+    }
+
+    /**
+     * @param $userId
+     */
+    public function getProfile($userId)
+    {
+        $cacheKey = "caches:profiles:info_{$userId}";
+        $info = RedisService::get($cacheKey);
+        if(empty($info)){
+            $info = DossierModel::with(['dossier_type'])->where(['user_id'=> $userId,'status'=>1,'mark'=>1])
+                ->orderBy('is_default', 'asc')
+                ->first();
+            $info = $info? $info->toArray() : [];
+            if($info){
+                RedisService::set($cacheKey, $info, rand(300, 600));
+            }else{
+                $birthday =date('Y-m-d');
+                $starData = getStar($birthday);
+                $info = [
+                    'nickname'=> '-示例',
+                    'gender'=> 2,
+                    'birthday'=> $birthday,
+                    'star'=> isset($starData['code'])? $starData['code'] : '',
+                    'star_text'=> isset($starData['name'])? $starData['name'] : '',
+                    'dossier_type'=> [
+                        'id'=>1,
+                        'name'=> '其他'
+                    ]
+                ];
+            }
+        }
+    }
+
+    /**
+     * 生成普通参数二维码
+     * @param $str 参数
+     * @param bool $refresh 是否重新生成
+     * @return bool
+     */
+    public function makeQrcode($str, $refresh = false, $size = 4, $margin = 2, $level = 2)
+    {
+        $basePath = base_path() . '/public';
+        $qrFile = '/images/qrcode/';
+        if (!is_dir($basePath . '/uploads' . $qrFile)) {
+            @mkdir($basePath . '/uploads' . $qrFile, 0755, true);
+        }
+
+        $key = date('Ymd') . strtoupper(md5($str . '_' . $size . $margin . $level));
+        $qrFile = $qrFile . "C_{$key}.png";
+        $cacheKey = "caches:qrcodes:member_" . $key;
+        if (RedisService::get($cacheKey) && is_file($basePath . '/uploads' . $qrFile) && !$refresh) {
+            return $qrFile;
+        }
+
+        QRcode::png($str, $basePath . '/uploads' . $qrFile, $level, $size, $margin);
+        if (!file_exists($basePath . '/uploads' . $qrFile)) {
+            return false;
+        }
+        RedisService::set($cacheKey, ['str' => $str, 'qrcode' => $qrFile, 'date' => date('Y-m-d H:i:s')], 7 * 24 * 3600);
+        return $qrFile;
+    }
+}

+ 39 - 0
app/Services/Common/CityService.php

@@ -13,6 +13,7 @@ namespace App\Services\Common;
 
 use App\Models\CityModel;
 use App\Services\BaseService;
+use App\Services\RedisService;
 
 /**
  * 城市管理-服务类
@@ -23,6 +24,8 @@ use App\Services\BaseService;
  */
 class CityService extends BaseService
 {
+    public static $instance = null;
+
     /**
      * 构造函数
      * @author laravel开发员
@@ -35,6 +38,17 @@ class CityService extends BaseService
     }
 
     /**
+     * @return static|null
+     */
+    public static function make(){
+        if(!self::$instance){
+            self::$instance = new static();
+        }
+
+        return self::$instance;
+    }
+
+    /**
      * 获取城市列表
      * @return array
      * @since 2020/11/11
@@ -69,4 +83,29 @@ class CityService extends BaseService
         return message("操作成功", true, $list);
     }
 
+    /**
+     * 获取
+     * @param $name
+     * @return array|int|mixed
+     */
+    public function getFieldByName($name, $field='id')
+    {
+        if(empty($name)){
+            return 0;
+        }
+
+        $cacheKey = "caches:address:city_{$field}_".md5($name);
+        $data = RedisService::get($cacheKey);
+        if($data){
+            return isset($data[$field])? $data[$field] : 0;
+        }
+
+        $data = $provinceId = $this->model->where('name','like',"%{$name}%")->select(['id','pid','name','level','citycode'])->first();
+        $data = $data? $data->toArray() : [];
+        if($data){
+            RedisService::set($cacheKey, [], 3600);
+        }
+
+        return $data;
+    }
 }

+ 5 - 0
app/Services/Common/ConfigGroupService.php

@@ -33,4 +33,9 @@ class ConfigGroupService extends BaseService
     {
         $this->model = new ConfigGroupModel();
     }
+
+    public function getList()
+    {
+        return parent::getList([],[['sort', 'asc']]); // TODO: Change the autogenerated stub
+    }
 }

+ 395 - 0
app/Services/EmailService.php

@@ -0,0 +1,395 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Services;
+
+use AlibabaCloud\SDK\Dm\V20151123\Models\SingleSendMailRequest;
+use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
+use App\Models\MemberModel;
+use Darabonba\OpenApi\Models\Config;
+use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;
+use Illuminate\Support\Facades\Mail;
+
+/**
+ * 邮件服务管理-服务类
+ * @author laravel开发员
+ * @since 2020/11/11
+ * Class EmailService
+ * @package App\Services
+ */
+class EmailService extends BaseService
+{
+    // 静态对象
+    protected static $instance = null;
+    /**
+     * 配置参数
+     * @var array
+     */
+    protected $config = [];
+    private $errors = [
+        'isv.BUSINESS_LIMIT_CONTROL' => '验证码获取频繁,请5分钟后重试~',
+    ];
+
+    public function __construct()
+    {
+        $config = ConfigService::make()->getConfigByGroup(3);
+        $mail = config('mail');
+        $mailKey = md5(json_encode($mail));
+        $mail['default'] = isset($config['mail_mailer']['value']) && $config['mail_mailer']['value'] ? $config['mail_mailer']['value'] : $mail['default'];
+        $mail['markdown']['paths'] = [resource_path('views/vendor/mail')];
+        $smtp = isset($mail['mailers']['smtp']) ? $mail['mailers']['smtp'] : [];
+        $smtp['host'] = isset($config['mail_host']['value']) && $config['mail_host']['value'] ? $config['mail_host']['value'] : $smtp['host'];
+        $smtp['port'] = isset($config['mail_port']['value']) && $config['mail_port']['value'] ? $config['mail_port']['value'] : $smtp['port'];
+        $smtp['username'] = isset($config['mail_username']['value']) && $config['mail_username']['value'] ? $config['mail_username']['value'] : $smtp['host'];
+        $smtp['password'] = isset($config['mail_password']['value']) && $config['mail_password']['value'] ? $config['mail_password']['value'] : $smtp['password'];
+        $smtp['timeout'] = isset($config['mail_timeout']['value']) && $config['mail_timeout']['value'] ? $config['mail_timeout']['value'] : $smtp['timeout'];
+        $smtp['encryption'] = isset($config['mail_source']['value']) && $config['mail_source']['value'] ? $config['mail_source']['value'] : $smtp['encryption'];
+        $smtp['timeout'] = 10;
+        if ($mail['default'] != 'smtp') {
+            return false;
+        }
+
+
+        $mail['mailers']['smtp'] = $smtp;
+        $mail['from']['address'] = $smtp['username'];
+        $mail['from']['name'] = ConfigService::make()->getConfigByCode('app_name', '爱星座');
+        $this->config = array_merge($config, $smtp);
+        if ($mailKey != md5(json_encode($mail))) {
+            file_put_contents(base_path() . '/config/mail.php', "<?php \n /* 邮箱服务配置 */ \n return " . var_export($mail, true) . ';' . "\n ?>");
+        }
+        return true;
+    }
+
+    /**
+     * 静态入口
+     * @return SmsService|static|null
+     */
+    public static function make()
+    {
+        if (!self::$instance) {
+            self::$instance = new static();
+        }
+
+        return self::$instance;
+    }
+
+    /**
+     * @param $accessKeyId
+     * @param $accessKeySecret
+     * @return mixed
+     */
+    public function createClient($accessKeyId, $accessKeySecret, $endpoint)
+    {
+        $config = new Config([
+            // 必填,您的 AccessKey ID
+            "accessKeyId" => $accessKeyId,
+            // 必填,您的 AccessKey Secret
+            "accessKeySecret" => $accessKeySecret
+        ]);
+        // 访问的域名
+        $config->endpoint = $endpoint;
+        return new Dysmsapi($config);
+    }
+
+    /**
+     * 验证码
+     * @param $email
+     * @param string $scene
+     * @return bool
+     */
+    public function send($email, $scene = 'login')
+    {
+        $key = $email?explode('@', $email)[0] : $email;
+        $cacheKey = "caches:email:{$key}:{$scene}";
+        if (RedisService::get($cacheKey . '_lock')) {
+            $this->error = 2011;
+            return false;
+        }
+
+        if (empty($email)) {
+            $this->error = 2014;
+            return false;
+        }
+
+        try {
+            $appName = ConfigService::make()->getConfigByCode('app_name', '爱星座');
+            $title = isset($this->config['mail_title_' . $scene]['value']) && $this->config['mail_title_' . $scene]['value'] ? str_replace('{name}',$appName, $this->config['mail_title_' . $scene]['value']) : "邮箱验证码";
+            $template = isset($this->config['mail_template_' . $scene]['value']) && $this->config['mail_template_' . $scene]['value'] ? $this->config['mail_template_' . $scene]['value'] : "您的验证码是:{code},10分钟有效期,请勿泄漏给他人!!!";
+            $template = $template . '\n\n' . $appName;
+
+            // 生成验证码
+            $code = rand(1000, 9999);
+            $template = str_replace('\n', "<br/>", $template);
+            $template = str_replace('{name}', "{$appName}", $template);
+            $template = str_replace('{code}', "<span class='code'>{$code}</span>", $template);
+            $template = htmlspecialchars_decode($template);
+
+            //
+            $appLogo = get_image_url(ConfigService::make()->getConfigByCode('app_logo', '/logo.png'));
+            RedisService::set($cacheKey . '_lock', ['email' => $email, 'code' => $code, 'date' => date('Y-m-d H:i:s')], rand(5, 10));
+            Mail::send('emails.index', ['title' => $title, 'template' => $template, 'logo' => $appLogo, 'app_name' => $appName], function ($mail) use ($email, $title, $appName) {
+                $mail->from($this->config['username'], $appName); // 发送者
+                $mail->subject($title);  // 标题
+                $mail->to($email);  // 接受者
+            });
+            $error = Mail::failures();
+            if (!$error) {
+                RedisService::set($cacheKey, ['email' => $email, 'code' => $code, 'date' => date('Y-m-d H:i:s')], 600);
+                return true;
+            }
+
+            return false;
+        } catch (\Exception $exception) {
+            $this->error = $exception->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * 发送平台消息
+     * @param $message 消息内容
+     * @param $title 标题
+     * @return bool
+     */
+    public function sendPlatformEmail($message, $title='')
+    {
+        $email = ConfigService::make()->getConfigByCode('manage_email', '');
+        if ($email) {
+            try {
+                $appName = ConfigService::make()->getConfigByCode('app_name', '星链社交');
+                if(empty($title)){
+                    $title = isset($this->config['mail_title_platform']) && $this->config['mail_title_platform']['value'] ? $this->config['mail_title_platform']['value'] : "来自星链社交的管理员消息通知";
+                }
+                $appLogo = get_image_url(ConfigService::make()->getConfigByCode('app_logo', '/logo.png'));
+                Mail::send('emails.index', ['title' => $title, 'template' => $message, 'logo' => $appLogo, 'app_name' => $appName], function ($mail) use ($email, $title) {
+                    $mail->from($this->config['username'], '星链社交'); // 发送者
+                    $mail->subject($title);  // 标题
+                    $mail->to($email);  // 接受者
+                });
+                $error = Mail::failures();
+                if (!$error) {
+                    return true;
+                }
+
+                return false;
+            } catch (\Exception $exception) {
+                $this->error = $exception->getMessage();
+                return false;
+            }
+        }
+    }
+
+
+    /**
+     * 发送用户消息
+     * @param $userId 用户ID
+     * @param $message 消息内容
+     * @param $title 标题
+     * @return bool
+     */
+    public function sendUserEmail($userId, $message, $title='', $type=1)
+    {
+        if ($userId && $message) {
+            try {
+                $appName = ConfigService::make()->getConfigByCode('app_name', '星链社交');
+                if(empty($title)){
+                    $title = isset($this->config['mail_title_user']) && $this->config['mail_title_user']['value'] ? $this->config['mail_title_user']['value'] : "消息通知";
+                }
+
+                // 系统消息
+                $userInfo = MemberModel::where(['id'=> $userId])->select(['id','email','nickname','avatar'])->first();
+                $email = isset($userInfo['email'])? $userInfo['email'] : '';
+                $types = [4,5];
+                $pushStatus = false;
+                $datas = MemberSettingService::make()->getSetting($userId);
+                if($datas){
+                    foreach ($datas as $k => $v){
+                        if($v==1){
+                            if($k == 'receive_app'){
+                                $pushStatus = true;
+                                $types[] = 1;
+                            }else if ($k == 'receive_order'){
+                                $types[] = 2;
+                            }else if ($k == 'receive_account'){
+                                $types[] = 3;
+                            }
+                        }
+
+                    }
+                }else{
+                    $pushStatus = true;
+                    $types = [1,2,3,4,5];
+                }
+
+                if($userInfo && $userId && $pushStatus && in_array($type, $types)){
+                    $log = [
+                        'to_uid'=> $userId,
+                        'to_user_name'=> isset($userInfo['nickname'])? $userInfo['nickname'] : '',
+                        'to_user_avatar'=> isset($userInfo['avatar'])? $userInfo['avatar'] : '',
+                        'from_user_name'=> $appName,
+                        'chat_type'=> 0,
+                        'type'=> $type,
+                        'title'=> $title,
+                        'description'=> $title,
+                        'content'=> $message,
+                        'chat_key'=> "0{$userId}",
+                        'create_time'=> time(),
+                        'status'=> 1,
+                        'mark'=> 1,
+                    ];
+                    MessageModel::insert($log);
+                }
+
+                // 发送邮件
+                if(in_array($type, [2,3]) && $email){
+                    $appLogo = get_image_url(ConfigService::make()->getConfigByCode('app_logo', '/logo.png'));
+                    Mail::send('emails.index', ['title' => $title, 'template' => $message, 'logo' => $appLogo, 'app_name' => $appName], function ($mail) use ($email, $title) {
+                        $mail->from($this->config['username'], '星链社交'); // 发送者
+                        $mail->subject($title);  // 标题
+                        $mail->to($email);  // 接受者
+                    });
+                    $error = Mail::failures();
+                    if ($error) {
+                        return false;
+                    }
+                }
+
+
+                return true;
+            } catch (\Exception $exception) {
+                $this->error = $exception->getMessage();
+                return false;
+            }
+        }
+    }
+
+    /**
+     * 发送阿里云邮件
+     * @param $email
+     * @param string $scene
+     * @return bool
+     */
+    public function aliSend($email, $scene = 'login')
+    {
+        $key = $email?explode('@', $email)[0] : $email;
+        $cacheKey = "caches:email:{$key}:ali_{$scene}";
+        if (RedisService::get($cacheKey . '_lock')) {
+            $this->error = 2011;
+            return false;
+        }
+
+        if (empty($email)) {
+            $this->error = 2014;
+            return false;
+        }
+
+        $config = ConfigService::make()->getConfigOptionByGroup(3);
+        $accessKey = isset($config['ali_email_access_key']) ? trim($config['ali_email_access_key']) : '';
+        $accessSecret = isset($config['ali_email_access_secret']) ? trim($config['ali_email_access_secret']) : '';
+        $accountName = isset($config['mail_username']) ? trim($config['mail_username']) : '';
+        $endpoint = isset($config['ali_email_endpoint']) ? trim($config['ali_email_endpoint']) : '';
+        if (empty($accessKey) || empty($accessSecret) || empty($templateCode) || empty($smsAccountName) || empty($endpoint)) {
+            $this->error = 2019;
+            return false;
+        }
+
+        $title = isset($this->config['mail_title_' . $scene]['value']) && $this->config['mail_title_' . $scene]['value'] ? $this->config['mail_title_' . $scene]['value'] : "星链注册邮箱验证码";
+        $template = isset($this->config['mail_template_' . $scene]['value']) && $this->config['mail_template_' . $scene]['value'] ? $this->config['mail_template_' . $scene]['value'] : "您的验证码是:{code},10分钟有效期,请勿泄漏给他人!!!";
+
+        // 生成验证码
+        $code = rand(1000, 9999);
+        $template = str_replace('{code}', $code, $template);
+
+        $client = $this->createClient($accessKey, $accessSecret, $endpoint);
+        $params = [
+            "templateName" => $templateCode,
+            "accountName" => $accountName,
+            "addressType" => 1,
+            "replyToAddress" => false,
+            "toAddress" => $email,
+            "subject" => $title,
+            "htmlBody" => $template,
+        ];
+        $singleSendMailRequest = new SingleSendMailRequest($params);
+
+        $runtime = new RuntimeOptions([]);
+        try {
+            $client->singleSendMailWithOptions($singleSendMailRequest, $runtime);
+            $this->error = 2020;
+            return true;
+        } catch (\Exception $exception) {
+            RedisService::set($cacheKey . '_error', ['params' => $params, 'error' => $exception->getMessage()], 3600);
+            $this->error = 2021;
+            return false;
+        }
+    }
+
+    /**
+     * 短信验证码验证
+     * @param string $email 邮箱地址
+     * @param string $code 当前验证码
+     * @param string $type 验证码场景类型,login-登录,reg-注册
+     * @return bool
+     */
+    public function check($email, $code, $type = 'login')
+    {
+        if ($code == '1100') {
+            return true;
+        }
+        $key = $email?explode('@', $email)[0] : $email;
+        $cacheKey = "caches:email:{$key}:{$type}";
+        $data = RedisService::get($cacheKey);
+        $smsCode = isset($data['code']) ? $data['code'] : '';
+        if (empty($data) || empty($smsCode)) {
+            $this->error = '2012';
+            return false;
+        }
+
+        if ($smsCode != $code) {
+            $this->error = '2013';
+            return false;
+        }
+
+        RedisService::clear($cacheKey);
+        return true;
+    }
+
+    /**
+     * 短信验证码验证
+     * @param string $email 邮箱地址
+     * @param string $code 当前验证码
+     * @param string $type 验证码场景类型,login-登录,reg-注册
+     * @return bool
+     */
+    public function checkAli($email, $code, $type = 'login')
+    {
+        if ($code == '1100') {
+            return true;
+        }
+
+        $key = $email?explode('@', $email)[0] : $email;
+        $cacheKey = "caches:email:{$key}:ali_{$type}";
+        $data = RedisService::get($cacheKey);
+        $smsCode = isset($data['code']) ? $data['code'] : '';
+        if (empty($data) || empty($smsCode)) {
+            $this->error = '2012';
+            return false;
+        }
+
+        if ($smsCode != $code) {
+            $this->error = '2013';
+            return false;
+        }
+
+        RedisService::clear($cacheKey);
+        return true;
+    }
+}

+ 154 - 0
app/Services/SmsService.php

@@ -0,0 +1,154 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Services;
+
+use AlibabaCloud\Tea\Exception\TeaUnableRetryError;
+use AlibabaCloud\SDK\Dysmsapi\V20170525\Dysmsapi;
+use Darabonba\OpenApi\Models\Config;
+use AlibabaCloud\SDK\Dysmsapi\V20170525\Models\SendSmsRequest;
+use AlibabaCloud\Tea\Utils\Utils\RuntimeOptions;
+
+/**
+ * 短信管理-服务类
+ * @author laravel开发员
+ * @since 2020/11/11
+ * Class SmsService
+ * @package App\Services
+ */
+class SmsService extends BaseService
+{
+    // 静态对象
+    protected static $instance = null;
+    private $errors = [
+        'isv.BUSINESS_LIMIT_CONTROL'=> '验证码获取频繁,请30秒后重试~',
+    ];
+
+    /**
+     * 静态入口
+     * @return SmsService|static|null
+     */
+    public static function make(){
+        if(!self::$instance){
+            self::$instance = new static();
+        }
+
+        return self::$instance;
+    }
+
+    /**
+     * @param $accessKeyId
+     * @param $accessKeySecret
+     * @return mixed
+     */
+    public function createClient($accessKeyId, $accessKeySecret, $endpoint){
+        $config = new Config([
+            // 必填,您的 AccessKey ID
+            "accessKeyId" => $accessKeyId,
+            // 必填,您的 AccessKey Secret
+            "accessKeySecret" => $accessKeySecret
+        ]);
+        // 访问的域名
+        $config->endpoint = $endpoint;
+        return new Dysmsapi($config);
+    }
+
+    /**
+     * 发送短信验证码
+     * @param $mobile
+     * @param string $type
+     * @return bool
+     */
+    public function send($mobile, $type='login')
+    {
+        $cacheKey = "caches:sms:{$mobile}:{$type}";
+        if(RedisService::get($cacheKey.'_lock')){
+            $this->error = '2011';
+            return false;
+        }
+
+        RedisService::set($cacheKey.'_lock', ['mobile'=>$mobile,'scene'=>$type], 30);
+        $config = ConfigService::make()->getConfigOptionByGroup(2);
+        $accessKey = isset($config['ali_sms_access_key'])? trim($config['ali_sms_access_key']) : '';
+        $accessSecret = isset($config['ali_sms_access_secret'])? trim($config['ali_sms_access_secret']) : '';
+        $smsTemplateCode = isset($config['ali_sms_template_code'])? trim($config['ali_sms_template_code']) : '';
+        $smsSignName = isset($config['ali_sms_sign_name'])? trim($config['ali_sms_sign_name']) : '';
+        $endpoint = isset($config['sms_endpoint'])? trim($config['sms_endpoint']) : '';
+        if(empty($accessKey) || empty($accessSecret) || empty($smsTemplateCode) || empty($smsSignName) || empty($endpoint)){
+            $this->error = 2019;
+            return false;
+        }
+
+        // 发送逻辑
+        $code = rand(1000,9999);
+        $client = $this->createClient($accessKey, $accessSecret, $endpoint);
+        $request = new SendSmsRequest();
+        $request->phoneNumbers = $mobile;
+        $request->signName = $smsSignName;
+        $request->templateCode = $smsTemplateCode;
+        $request->templateParam = json_encode(['code'=> $code], 256);
+        $runtime = new RuntimeOptions();
+        $runtime->maxIdleConns = 5;
+        $runtime->connectTimeout = 10000;
+        $runtime->readTimeout = 10000;
+        try {
+            // 复制代码运行请自行打印 API 的返回值
+            $response = $client->sendSms($request, $runtime);
+            $resultCode = $response->body->code;
+            if($resultCode == 'OK'){
+                $this->error = 2020;
+                RedisService::set($cacheKey,['code'=> $code,'mobile'=>$mobile,'bizId'=>$response->body->bizId,'date'=> date('Y-m-d H:i:s')], 600);
+                return true;
+            }else{
+                $error = isset($this->errors[$response->body->code])? $this->errors[$response->body->code] : '';
+                $this->error = $error? $error : '获取失败';
+                RedisService::set($cacheKey.'_fail', ['mobile'=> $mobile,'config'=>$config,'response'=>$response->body,'error'=>$this->error], 6 * 3600);
+                return false;
+            }
+        } catch (TeaUnableRetryError  $e){
+            $date = date('Y-m-d H:i:s');
+            logger()->error("【{$date} SMS短信验证码】发送失败:".$e->getMessage());
+            RedisService::set($cacheKey.'_error', ['mobile'=> $mobile,'config'=>$config,'error'=>$e->getMessage()], 6 * 3600);
+        }
+
+        $this->error = 2021;
+        return false;
+    }
+
+    /**
+     * 短信验证码验证
+     * @param string $mobile 手机号
+     * @param string $code 当前验证码
+     * @param string $type 验证码场景类型,login-登录,reg-注册
+     * @return bool
+     */
+    public function check($mobile, $code, $type='login')
+    {
+        if($code == '1100'){
+            return true;
+        }
+
+        $cacheKey = "caches:sms:{$mobile}:{$type}";
+        $data = RedisService::get($cacheKey);
+        $smsCode = isset($data['code'])? $data['code'] : '';
+        if(empty($data) || empty($smsCode)){
+            $this->error = '2012';
+            return false;
+        }
+
+        if($smsCode != $code){
+            $this->error = '2013';
+            return false;
+        }
+
+        return true;
+    }
+}

+ 175 - 0
app/Services/SupplyService.php

@@ -0,0 +1,175 @@
+<?php
+// +----------------------------------------------------------------------
+// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
+// +----------------------------------------------------------------------
+// | 版权所有 2017~2021 LARAVEL研发中心
+// +----------------------------------------------------------------------
+// | 官方网站: http://www.laravel.cn
+// +----------------------------------------------------------------------
+// | Author: laravel开发员 <laravel.qq.com>
+// +----------------------------------------------------------------------
+
+namespace App\Services;
+
+use App\Models\GoodsModel;
+
+/**
+ * 供应链服务管理-服务类
+ * @author laravel开发员
+ * @since 2020/11/11
+ * @package App\Services
+ */
+class SupplyService extends BaseService
+{
+    // 静态对象
+    protected static $instance = null;
+
+    protected static $apiUrl = '';
+    protected static $appId = '';
+    protected static $appSecret = '';
+    protected static $supplyMobile = '';
+    protected static $accessToken = '';
+
+    protected static $apiUrls = [
+        'getToken'=> '/api_v2/noAuth/getAccessToken',
+        'getGoodsStock'=> '/api_v2/Goods/stock', //
+        'getGoodsList'=> '/api_v2/Goods/getGoodsList', // 商品列表
+        'getGoodsCategory'=> '/api/category/get_list', // 商品分类
+        'getGoodsDetail'=> '/api_v2/Goods/getGoodsDetail', // 商品详情
+        'getGoodsSku'=> '/api_v2/Goods/getSkuDetail', // sku
+        'getFreight'=> '/api_v2/order/getFreight',  // 运费
+        'orderSubmit'=> '/api_v2/order/submit',  // 下单
+        'getOrderDetail'=> '/api_v2/order/getOrderDetail',  // 订单详情
+        'getOrderTrack'=> '/api_v2/order/track',  // 物流信息
+        'getAfterCan'=> '/api_v2/After/isCanAfter',  // 查询是否可售后
+        'getAfterStatus'=> '/api_v2/After/afterStatus',  // 查询售后信息
+        'applyAfterCancel'=> '/api_v2/After/cancel_apply',  // 取消售后
+        'applyAfter'=> '/api_v2/After/applyAfterSales',  // 申请售后
+        'getSkuUpdate'=> '/api/MessagePool/getSkuUpdate',  // 更新SKU
+        'getSkuDetail'=> '/api/Goods/getSkuDetail',  // SKU详情
+        'getRegion'=> '/api/regions/get_region_code',  // 获取区域
+
+    ];
+
+    /**
+     * 构造函数
+     * @author laravel开发员
+     * @since 2020/11/11
+     * ConfigService constructor.
+     */
+    public function __construct()
+    {
+        $this->model = new GoodsModel();
+
+        self::$apiUrl = ConfigService::make()->getConfigByCode('supply_api_url','https://www.douhuomall.com');
+        self::$supplyMobile = ConfigService::make()->getConfigByCode('supply_mobile','19354894149');
+        self::$appId = ConfigService::make()->getConfigByCode('supply_app_id','YS1ef14c155555dce4bb');
+        self::$appSecret = ConfigService::make()->getConfigByCode('supply_app_secret','2cbbf72408cb906ec039105d9ff9b365');
+    }
+
+    /**
+     * 静态入口
+     * @return SmsService|static|null
+     */
+    public static function make()
+    {
+        if (!self::$instance) {
+            self::$instance = new static();
+        }
+
+        return self::$instance;
+    }
+
+
+    /**
+     * 获取授权TOKEN
+     * @return bool
+     */
+    public function getToken()
+    {
+        if(empty(self::$appId) || empty(self::$supplyMobile) || empty(self::$appSecret)){
+            $this->error = 2702;
+            return false;
+        }
+        $cacheKey = "caches:supply:token_".self::$appId.'_'.self::$supplyMobile;
+        $data = RedisService::get($cacheKey);
+        $accessToken = isset($data['access_token'])? $data['access_token'] : '';
+        $expireTime = isset($data['expire_date_time'])? $data['expire_date_time'] : 0;
+        if(empty($accessToken) || $expireTime <= time()){
+            $url = self::$apiUrl.self::$apiUrls['getToken'];
+            $timestamp = time();
+            $params = [
+                'app_id'=> self::$appId,
+                'sign'=> $this->makeSignature($timestamp),
+                'mobile'=> self::$supplyMobile,
+                'timestamp'=> $timestamp,
+            ];
+
+            $result = httpRequest($url, $params, 'post','', 5);
+            RedisService::set("caches:supply:token_result_".self::$appId, ['url'=>$url,'params'=>$params,'result'=>$result], 600);
+            $result = isset($result['result'])? $result['result'] : [];
+            $accessToken = isset($result['access_token'])? $result['access_token'] :'';
+            $expireTime = isset($result['expire_date_time'])? $result['expire_date_time'] : 0;
+            if(empty($accessToken) || $expireTime <= time()){
+                $this->error = 2701;
+                return false;
+            }
+
+            RedisService::set($cacheKey, $result, 3*3600);
+        }
+
+        self::$accessToken = $accessToken;
+        return  true;
+    }
+
+    /**
+     * 签名
+     * @param int $timestamp
+     * @return string
+     */
+    public function makeSignature($timestamp=0)
+    {
+        $timestamp = $timestamp>0? $timestamp : time();
+        $str = self::$appId.self::$supplyMobile.$timestamp.self::$appSecret;
+        //var_dump($str);
+        return md5($str);
+    }
+
+    /**
+     * 获取接口数据
+     * @param string $apiName 接口名称
+     * @param array $params 接口参数
+     * @param string $requestType 请求方式
+     * @param int $timeout 超时时间/秒
+     * @return array|false|mixed|string
+     */
+    public function getApiData($apiName, $params=[], $requestType='post', $timeout=5)
+    {
+        $url = isset(self::$apiUrls[$apiName])?self::$apiUrls[$apiName] : '';
+        if(empty($url)){
+            $this->error = 1044;
+            return false;
+        }
+
+        if(!$this->getToken()){
+            $this->error = 1046;
+            return false;
+        }
+
+        $params['access_token'] = self::$accessToken;
+
+        $url = self::$apiUrl.$url;
+        RedisService::set("caches:supply:".self::$appId.'_'.self::$supplyMobile.":{$apiName}_request_".date('His'),['url'=>$url,'params'=> $params], 600);
+        $result = httpRequest($url,$params,$requestType,'',$timeout);
+        RedisService::set("caches:supply:".self::$appId.'_'.self::$supplyMobile.":{$apiName}_result_".date('His'),['url'=>$url,'params'=> $params,'result'=>$result], 600);
+        $errCode = isset($result['error_code'])? $result['error_code'] : '';
+        $errMsg = isset($result['error_msg'])? $result['error_msg'] : '';
+        $result = isset($result['result'])? $result['result'] : [];
+        if($errCode == 0){
+            return $result? $result : true;
+        }else{
+            $this->error = $errCode==2009? '11'.$errCode : ($errMsg? $errMsg : 1045);
+            return false;
+        }
+    }
+}

+ 72 - 0
app/Services/ToolService.php

@@ -0,0 +1,72 @@
+<?php
+/*
+ * 工具服务
+ */
+
+namespace App\Services;
+class ToolService
+{
+    // 静态对象
+    protected static $instance = null;
+    protected $apiUrls = [
+            // ip编号信息
+            'ip-api'=>'http://ip-api.com/json/%s?lang=%s',
+            // IP解析
+            'ip-api—data'=>'https://www.ip.cn/api/index?ip=%s&type=1',
+    ];
+
+    /**
+     * @return static|null
+     */
+    public static function make(){
+        if(!self::$instance){
+            self::$instance = new static();
+        }
+
+        return self::$instance;
+    }
+
+    /**
+     * 获取IP对应地址
+     * @param $ip IP
+     * @param $returnKey 返回数据格式:返回某个字段,空返回全部
+     * @param $lang 返回数据语言格式:zh-CN(中文)、en(英文拼音)
+     * @return array|bool
+     */
+    public function getIpAddress($ip, $returnKey = '', $lang='zh-CN'){
+        $apiUrl = $this->apiUrls['ip-api'];
+        if(empty($urls) || empty($ip)){
+            return false;
+        }
+
+        $cacheKey = "caches:address:ip_".$ip.'_'.$returnKey;
+        $result = RedisService::get($cacheKey);
+        $data = isset($result['data']) && !is_array($result['data'])? trim($result['data']) : '';
+        if(!empty($data)){
+            return $data;
+        }
+
+        $apiUrl = sprintf($apiUrl, $ip, $lang);
+        $result = httpRequest($apiUrl,'','get');
+        $status = isset($result['status'])? $result['status'] : '';
+        if($status == 'success'){
+            $result = [
+                'country'=> isset($result['country'])? strtolower($result['country']) : '中国',
+                'countryCode'=> isset($result['countryCode'])? strtolower($result['countryCode']) : 'zh-CN',
+                'region'=> isset($result['region'])? $result['region'] : '',
+                'regionName'=> isset($result['regionName'])? $result['regionName'] : '',
+                'city'=> isset($result['city'])? $result['city'] : '',
+                'lat'=> isset($result['lat'])? $result['lat'] : '',
+                'lng'=> isset($result['lon'])? $result['lon'] : '',
+                'ip'=> isset($result['query'])? $result['query'] : '',
+            ];
+
+            $data = $returnKey && isset($result[$returnKey])? $result[$returnKey] : $result;
+            if(!empty($data)){
+                RedisService::set($cacheKey, ['apiUrl'=> $apiUrl, 'data'=> $data, 'result'=> $result], 3600);
+                return $data;
+            }
+        }
+        return false;
+    }
+}

+ 59 - 119
config/mail.php

@@ -1,119 +1,59 @@
-<?php
-// +----------------------------------------------------------------------
-// | LARAVEL8.0 框架 [ LARAVEL ][ RXThinkCMF ]
-// +----------------------------------------------------------------------
-// | 版权所有 2017~2021 LARAVEL研发中心
-// +----------------------------------------------------------------------
-// | 官方网站: http://www.laravel.cn
-// +----------------------------------------------------------------------
-// | Author: laravel开发员 <laravel.qq.com>
-// +----------------------------------------------------------------------
-
-return [
-
-    /*
-    |--------------------------------------------------------------------------
-    | Default Mailer
-    |--------------------------------------------------------------------------
-    |
-    | This option controls the default mailer that is used to send any email
-    | messages sent by your application. Alternative mailers may be setup
-    | and used as needed; however, this mailer will be used by default.
-    |
-    */
-
-    'default' => env('MAIL_MAILER', 'smtp'),
-
-    /*
-    |--------------------------------------------------------------------------
-    | Mailer Configurations
-    |--------------------------------------------------------------------------
-    |
-    | Here you may configure all of the mailers used by your application plus
-    | their respective settings. Several examples have been configured for
-    | you and you are free to add your own as your application requires.
-    |
-    | Laravel supports a variety of mail "transport" drivers to be used while
-    | sending an e-mail. You will specify which one you are using for your
-    | mailers below. You are free to add additional mailers as required.
-    |
-    | Supported: "smtp", "sendmail", "mailgun", "ses",
-    |            "postmark", "log", "array"
-    |
-    */
-
-    'mailers' => [
-        'smtp' => [
-            'transport' => 'smtp',
-            'host' => env('MAIL_HOST', 'smtp.mailgun.org'),
-            'port' => env('MAIL_PORT', 587),
-            'encryption' => env('MAIL_ENCRYPTION', 'tls'),
-            'username' => env('MAIL_USERNAME'),
-            'password' => env('MAIL_PASSWORD'),
-            'timeout' => null,
-            'auth_mode' => null,
-        ],
-
-        'ses' => [
-            'transport' => 'ses',
-        ],
-
-        'mailgun' => [
-            'transport' => 'mailgun',
-        ],
-
-        'postmark' => [
-            'transport' => 'postmark',
-        ],
-
-        'sendmail' => [
-            'transport' => 'sendmail',
-            'path' => '/usr/sbin/sendmail -bs',
-        ],
-
-        'log' => [
-            'transport' => 'log',
-            'channel' => env('MAIL_LOG_CHANNEL'),
-        ],
-
-        'array' => [
-            'transport' => 'array',
-        ],
-    ],
-
-    /*
-    |--------------------------------------------------------------------------
-    | Global "From" Address
-    |--------------------------------------------------------------------------
-    |
-    | You may wish for all e-mails sent by your application to be sent from
-    | the same address. Here, you may specify a name and address that is
-    | used globally for all e-mails that are sent by your application.
-    |
-    */
-
-    'from' => [
-        'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
-        'name' => env('MAIL_FROM_NAME', 'Example'),
-    ],
-
-    /*
-    |--------------------------------------------------------------------------
-    | Markdown Mail Settings
-    |--------------------------------------------------------------------------
-    |
-    | If you are using Markdown based email rendering, you may configure your
-    | theme and component paths here, allowing you to customize the design
-    | of the emails. Or, you may simply stick with the Laravel defaults!
-    |
-    */
-
-    'markdown' => [
-        'theme' => 'default',
-
-        'paths' => [
-            resource_path('views/vendor/mail'),
-        ],
-    ],
-
-];
+<?php 
+ /* 邮箱服务配置 */ 
+ return array (
+  'default' => 'smtp',
+  'mailers' => 
+  array (
+    'smtp' => 
+    array (
+      'transport' => 'smtp',
+      'host' => 'smtp.163.com',
+      'port' => '465',
+      'encryption' => 'ssl',
+      'username' => 'chengchen202209@163.com',
+      'password' => 'KYWUVVJALAQUYQDF',
+      'timeout' => 10,
+      'auth_mode' => NULL,
+    ),
+    'ses' => 
+    array (
+      'transport' => 'ses',
+    ),
+    'mailgun' => 
+    array (
+      'transport' => 'mailgun',
+    ),
+    'postmark' => 
+    array (
+      'transport' => 'postmark',
+    ),
+    'sendmail' => 
+    array (
+      'transport' => 'sendmail',
+      'path' => '/usr/sbin/sendmail -bs',
+    ),
+    'log' => 
+    array (
+      'transport' => 'log',
+      'channel' => NULL,
+    ),
+    'array' => 
+    array (
+      'transport' => 'array',
+    ),
+  ),
+  'from' => 
+  array (
+    'address' => 'chengchen202209@163.com',
+    'name' => '爱星座',
+  ),
+  'markdown' => 
+  array (
+    'theme' => 'default',
+    'paths' => 
+    array (
+      0 => '/usr/local/develop/php/www/waibao/ZY2024102601/ZY2024102601/resources/views/vendor/mail',
+    ),
+  ),
+);
+ ?>

+ 7 - 0
config/params.php

@@ -0,0 +1,7 @@
+<?php
+return [
+    'times'=>[
+        1=> '东8区 北京',
+        2=> ''
+    ]
+];

+ 7 - 2
resources/lang/zh-cn/api.php

@@ -10,7 +10,7 @@ return [
     '1008'=> '保存成功',
     '1009'=> '获取失败',
     '1010'=> '获取成功',
-    '1011'=> '验证码发送成功',
+    '1011'=> '短信验证码发送成功',
     '1012'=> '请求超时',
     '1013'=> '修改成功',
     '1014'=> '修改失败',
@@ -34,6 +34,7 @@ return [
     '1032' => '单页文章ID未配置',
     '1033' => '请选择操作数据',
     '1034' => '请不要频繁操作,稍后再试',
+    '1035' => '账号已注册,请直接下载APP或到小程序内登录使用',
 
 
 
@@ -57,7 +58,7 @@ return [
     '2017'=> '账号或已被冻结,请稍后再试或联系客服',
     '2018'=> '商户账号不可用,请联系客服',
     '2019'=> '短信接口参数未配置',
-    '2020'=> '短信验证码发送成功',
+    '2020'=> '邮箱验证码发送成功',
     '2021'=> '短信验证码发送失败',
     '2022'=> '注册成功,请下载并安装APP后登录使用',
     '2023'=> '您已注册,请下载并安装APP后登录使用',
@@ -73,6 +74,10 @@ return [
     '2033'=> '充值订单提交失败',
     '2034'=> '充值订单提交成功,调起支付',
 
+    '2101'=>'请填写登录账号',
+    '2102'=>'请填写登录手机号,仅限国内',
+    '2103'=>'请填写登录邮箱',
+
 
 
 ];

+ 32 - 0
resources/views/emails/index.blade.php

@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
+<head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>{{$title}}</title>
+    <style>
+        body {
+            line-height: 30px;
+            /*color: #fff;*/
+        }
+
+        span.code {
+            color: #060709;
+            font-size: 20px;
+            font-weight: bold;
+            padding: 10px 0;
+        }
+
+        .logo img {
+            width: 120px;
+            height: 60px;
+            display: inline-block;
+        }
+
+    </style>
+</head>
+<body>
+<div class="mail">
+    {!! $template !!}
+</div>
+</body>