فهرست منبع

Weenier 168otc项目部署 0630

wesmiler 3 سال پیش
والد
کامیت
d277bfb88b

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

@@ -130,8 +130,8 @@ class IndexController extends Backend
         $datas = [
             'counts'=> [
                 'usdt_num'=> isset($userInfo['usdt_num'])? moneyFormat($userInfo['usdt_num'], 2) : '0.00',
-                'buy_total'=> TradeOrderService::make()->getCompleteTotal(1, $this->userInfo['user_id']),
-                'sell_total'=> TradeOrderService::make()->getCompleteTotal(2, $this->userInfo['user_id']),
+                'buy_total'=> TradeOrderService::make()->getCompleteTotalByDay(1, $this->userInfo['user_id']),
+                'sell_total'=> TradeOrderService::make()->getCompleteTotalByDay(2, $this->userInfo['user_id']),
                 'day_sell_quota'=> isset($setting['day_sell_quota'])? floatval($setting['day_sell_quota']) : '0.00',
                 'buy_rate'=> isset($counts['buy_rate'])? $counts['buy_rate'] : '0.00',
                 'sell_rate'=> isset($counts['sell_rate'])? $counts['sell_rate'] : '0.00',

+ 30 - 0
app/Http/Controllers/Admin/TradeOrderController.php

@@ -34,5 +34,35 @@ class TradeOrderController extends Backend
     }
 
 
+    public function index()
+    {
+        $params = request()->all();
+        $pageSize = request()->post('pageSize', 15);
+        if($this->userInfo['user_type'] == 2){
+            $params['business_id'] = $this->userInfo['user_id'];
+        }
+        $list = TradeOrderService::make()->getDataList($params,$pageSize);
+        $message = array(
+            "msg" => '操作成功',
+            "code" => 0,
+            "data" => isset($list['list'])? $list['list']:[],
+            "count" => isset($list['total'])? $list['total']:0,
+        );
+        return $message;
+    }
 
+    public function business()
+    {
+        $params = request()->all();
+        $pageSize = request()->post('pageSize', 15);
+        $params['business_id'] = $this->userInfo['user_id'];
+        $list = TradeOrderService::make()->getDataList($params,$pageSize);
+        $message = array(
+            "msg" => '操作成功',
+            "code" => 0,
+            "data" => isset($list['list'])? $list['list']:[],
+            "count" => isset($list['total'])? $list['total']:0,
+        );
+        return $message;
+    }
 }

+ 4 - 2
app/Http/Controllers/Api/IndexController.php

@@ -85,9 +85,9 @@ class IndexController extends webApp
         $from = request()->post('from','');
         $to = request()->post('to','');
         $amount = request()->post('amount','');
-        $result = UsdtWalletService::make()->trxTransfer($from, $to, $amount);
-
+        $result = UsdtWalletService::make()->getWebAddress();
 
+var_dump($result);
     }
 
     public function transfer(){
@@ -116,4 +116,6 @@ class IndexController extends webApp
         var_dump($result);
         var_dump(UsdtWalletService::make()->getError());
     }
+
+
 }

+ 2 - 0
app/Http/Controllers/Api/TaskController.php

@@ -103,4 +103,6 @@ class TaskController extends webApp
             return showJson(1021, false);
         }
     }
+
+
 }

+ 15 - 2
app/Http/Controllers/Api/TestController.php

@@ -2,9 +2,11 @@
 
 namespace App\Http\Controllers\Api;
 
+use App\Services\Api\MemberService;
 use App\Services\ConfigService;
 use App\Services\EmailService;
 use App\Services\RedisService;
+use App\Services\UsdtWalletService;
 use Illuminate\Http\Request;
 
 /**
@@ -15,10 +17,21 @@ use Illuminate\Http\Request;
 class TestController extends webApp
 {
 
-    public function index()
+    public function business()
     {
-
+        $num = request()->all('num');
+        $tradeType = request()->post('type');
+        $result = MemberService::make()->getTradeMember($num, $tradeType);
+        var_dump($result);
     }
 
+    public function index()
+    {
+        $result = UsdtWalletService::make()->usdtTrcTrigger(true);
+        if(!$result){
+            return message(UsdtWalletService::make()->getError(), false);
+        }
 
+        var_dump($result);
+    }
 }

+ 93 - 0
app/Http/Controllers/Api/TradeController.php

@@ -0,0 +1,93 @@
+<?php
+
+namespace App\Http\Controllers\Api;
+
+use App\Http\Validator\TradeValidator;
+use App\Services\Common\TradeOrderService;
+use App\Services\ConfigService;
+use App\Services\EmailService;
+use App\Services\RedisService;
+use Illuminate\Http\Request;
+
+/**
+ * 交易
+ * Class TradeController
+ * @package App\Http\Controllers\Api
+ */
+class TradeController extends webApp
+{
+    /**
+     * 构造函数
+     * @author laravel开发员
+     * @since 2020/11/11
+     * NoticeController constructor.
+     */
+    public function __construct()
+    {
+        parent::__construct();
+        $this->service = new TradeOrderService();
+    }
+
+    /**
+     * 用户交易订单
+     * @return array|mixed
+     */
+    public function index()
+    {
+        $params = request()->all();
+        $pageSize = request()->post('pageSize', 15);
+        $params['user_id'] = $this->userId;
+        $list = TradeOrderService::make()->getDataList($params,$pageSize);
+        return message(1010, true,  $list);
+    }
+
+    /**
+     * 承兑商交易订单
+     * @return array
+     */
+    public function business()
+    {
+        $params = request()->all();
+        $pageSize = request()->post('pageSize', 15);
+        $params['business_id'] = $this->userId;
+        $list = TradeOrderService::make()->getDataList($params,$pageSize);
+        return message(1010, true,  $list);
+    }
+
+    /**
+     * 买入
+     * @param TradeValidator $validate
+     * @return array
+     */
+    public function buy(TradeValidator $validate)
+    {
+        $params = request()->post();
+        $params = $validate->check($params,'buy');
+        if(!is_array($params)){
+            return message($params, false);
+        }
+
+        if($info = TradeOrderService::make()->buy($this->userId, $params)){
+            return message(3006, true, $info);
+        }else{
+            return message(TradeOrderService::make()->getError(), false);
+        }
+    }
+
+
+    public function sell(TradeValidator $validate)
+    {
+        $params = request()->post();
+        $params = $validate->check($params,'sell');
+        if(!is_array($params)){
+            return message($params, false);
+        }
+
+        if($info = TradeOrderService::make()->sell($this->userId, $params)){
+            return message(3007, true, $info);
+        }else{
+            return message(TradeOrderService::make()->getError(), false);
+        }
+    }
+
+}

+ 52 - 0
app/Http/Validator/TradeValidator.php

@@ -0,0 +1,52 @@
+<?php
+namespace App\Http\Validator;
+class TradeValidator extends BaseValidator
+{
+    // 当前模型所有验证规则
+    public static $rules = [
+        'id' => 'required',
+        'trade_type' => 'required',
+        'num_type' => 'required',
+        'pay_type' => 'required',
+        'payment_id' => 'required',
+        'num' => 'required',
+    ];
+
+    // 当前模型所有错误提示信息
+    public static $msgs = [
+        'required' => ':attribute不能为空',
+        'string' => ':attribute必须是字符串',
+        'min' => ':attribute长度不能小于:min位',
+        'max' => ':attribute长度不能大于:max位',
+        'exists' => ':attribute不存在',
+        'rule' => ':attribute格式不正确',
+    ];
+
+    // 当前模型所有验证字段
+    public static $fields = [
+        'id' => 'ID',
+        'trade_type' => '交易类型',
+        'num_type' => '交易数值类型',
+        'pay_type' => '支付方式',
+        'payment_id' => '收款账号',
+        'num' => '数量或金额',
+    ];
+
+    // 当前模型所有验证场景
+    public static $scenes = [
+        'info'=> ['id'],
+        'buy'=> ['trade_type','pay_type','num_type','num'],
+        'sell'=> ['trade_type','payment_id','num_type','num'],
+    ];
+
+    /**
+     * 验证
+     * @param $request
+     * @param string $scene
+     * @return int|mixed
+     */
+    public static function check($request, $scene=''){
+        $validator = new BaseValidator(self::$rules, self::$msgs, self::$fields, self::$scenes);
+        return $validator->checkParams($request, $scene);
+    }
+}

+ 49 - 0
app/Jobs/Timer/OrderJob.php

@@ -0,0 +1,49 @@
+<?php
+
+namespace App\Jobs\Timer;
+
+
+use Hhxsv5\LaravelS\Swoole\Timer\CronJob;
+use Illuminate\Support\Facades\Log;
+use Swoole\Timer;
+
+class OrderJob extends CronJob
+{
+    public function interval()
+    {
+        // 5分钟执行一次
+        return 5 * 60 * 1000;   // 定时器间隔,单位为 ms
+    }
+
+    /**
+     * @return bool
+     */
+    public function isImmediate()
+    {
+        return $this->isImmediate;
+    }
+
+    public function setTimerId($timerId)
+    {
+        $this->timerId = $timerId;
+    }
+
+    public function stop()
+    {
+        if ($this->timerId && Timer::exists($this->timerId)) {
+            Timer::clear($this->timerId);
+        }
+    }
+
+    /**
+     * 运行
+     */
+    public function run()
+    {
+        Log::info(__METHOD__, ['start', '', microtime(true)]);
+
+
+
+        $this->stop();
+    }
+}

+ 4 - 1
app/Models/BaseModel.php

@@ -613,7 +613,10 @@ class BaseModel extends CacheModel
         // 对象转数组
         $data = object_array($list);
         foreach ($data as $v) {
-            $tables[] = $v["Tables_in_{$database}"];
+
+            if(isset($v["Tables_in_{$database}"]) && $v["Tables_in_{$database}"]){
+                $tables[] = $v["Tables_in_{$database}"];
+            }
         }
         return $tables;
     }

+ 162 - 54
app/Services/Api/MemberService.php

@@ -10,12 +10,18 @@
 // +----------------------------------------------------------------------
 
 namespace App\Services\Api;
+
 use App\Helpers\Jwt;
 use App\Models\ActionLogModel;
 use App\Models\MemberModel;
 use App\Services\BaseService;
+use App\Services\Common\MemberSettingService;
+use App\Services\ConfigService;
 use App\Services\RedisService;
 use App\Services\UsdtWalletService;
+use Illuminate\Support\Facades\DB;
+use phpQrcode\QRcode;
+
 
 /**
  * 会员-服务类
@@ -43,7 +49,7 @@ class MemberService extends BaseService
      */
     public static function make()
     {
-        if(!self::$instance){
+        if (!self::$instance) {
             self::$instance = (new static());
         }
         return self::$instance;
@@ -54,23 +60,33 @@ class MemberService extends BaseService
      * @param $where
      * @param array $field
      */
-    public function getInfo($where, array $field=[])
+    public function getInfo($where, array $field = [])
     {
-        $field = $field? $field : ['id','username','realname','nickname','openid','idcard','trc_address','erc_address','source','idcard_check','idcard_front_img','idcard_back_img','safe_level','user_type','member_level','usdt_num','user_type','status','credit','avatar'];
-        if(is_array($where)){
+        $field = $field ? $field : ['id', 'username', 'realname', 'nickname', 'openid', 'idcard', 'trc_address', 'erc_address', 'source', 'idcard_check', 'idcard_front_img', 'idcard_back_img', 'safe_level', 'user_type', 'member_level', 'usdt_num', 'user_type', 'status', 'credit', 'avatar'];
+        if (is_array($where)) {
             $info = $this->model->where($where)->select($field)->first();
-        }else{
-            $info = $this->model->where(['id'=> (int)$where])->select($field)->first();
+        } else {
+            $info = $this->model->where(['id' => (int)$where])->select($field)->first();
         }
 
-        $info = $info? $info->toArray() : [];
-        if($info){
+        $info = $info ? $info->toArray() : [];
+        if ($info) {
+            $tradePrice = ConfigService::make()->getConfigByCode('usdt_sell_price');
+            $tradePrice = $tradePrice? $tradePrice : 0;
 
-            $info['avatar'] = $info['avatar']? get_image_url($info['avatar']) : '';
-            $info['idcard_front_img'] = $info['idcard_front_img']? get_image_url($info['idcard_front_img']) : '';
-            $info['idcard_back_img'] = $info['idcard_back_img']? get_image_url($info['idcard_back_img']) : '';
-            $info['usdt_num'] = isset($info['usdt_num'])? moneyFormat($info['usdt_num'], 4) : '0.0000';
+            $info['avatar'] = $info['avatar'] ? get_image_url($info['avatar']) : '';
+            $info['idcard_front_img'] = $info['idcard_front_img'] ? get_image_url($info['idcard_front_img']) : '';
+            $info['idcard_back_img'] = $info['idcard_back_img'] ? get_image_url($info['idcard_back_img']) : '';
+            $info['usdt_num'] = isset($info['usdt_num']) ? moneyFormat($info['usdt_num'], 4) : '0.0000';
+            $info['cny_num'] = $info['usdt_num'] && $tradePrice>0? moneyFormat($info['usdt_num']*$tradePrice, 6) : '0.0000';
             $info['is_collection'] = MemberPaymentService::make()->checkHasByUser($info['id']);
+
+            // 收款二维码
+             $qrcode = $this->makeQrcode($info['trc_address']);
+            $info['trc_qrcode'] = $qrcode? get_image_url($qrcode) : '';
+            $ercQrcode = $this->makeQrcode($info['erc_address']);
+            $info['erc_qrcode'] = $ercQrcode? get_image_url($ercQrcode) : '';
+
         }
 
         return $info;
@@ -84,47 +100,48 @@ class MemberService extends BaseService
     public function register($params)
     {
         // 检测账号是否存在
-        if($this->checkExists('username', $params['username'])){
+        if ($this->checkExists('username', $params['username'])) {
             $this->error = '2005';
             return false;
         }
 
-        $username = isset($params['username'])? trim($params['username']) : '';
-        $password = isset($params['password'])? trim($params['password']) : '123456';
-        $avatar = isset($params['avatar'])? trim($params['avatar']) : '';
+        $username = isset($params['username']) ? trim($params['username']) : '';
+        $password = isset($params['password']) ? trim($params['password']) : '123456';
+        $avatar = isset($params['avatar']) ? trim($params['avatar']) : '';
         $data = [
-            'username'=> $username,
-            'password'=> get_password($password . $username),
-            'mobile'=> isPhone($username)? $username : '',
-            'avatar'=> $avatar? $avatar : '',
-            'status'=> 1,
-            'mark'=> 1,
-            'create_time'=> time(),
+            'username' => $username,
+            'password' => get_password($password . $username),
+            'mobile' => isPhone($username) ? $username : '',
+            'avatar' => $avatar ? $avatar : '',
+            'status' => 1,
+            'mark' => 1,
+            'create_time' => time(),
         ];
 
         // 生成trc2.0钱包地址
         $trcAddress = UsdtWalletService::make()->getTrxAddress();
-        if($trcAddress){
-            $data['trc_wif'] = isset($trcAddress['wif'])? $trcAddress['wif'] : '';
-            $data['trc_hexaddress'] = isset($trcAddress['hexAddress'])? $trcAddress['hexAddress'] : '';
-            $data['trc_address'] = isset($trcAddress['address'])? $trcAddress['address'] : '';
-        }else{
+        if ($trcAddress) {
+            $data['trc_wif'] = isset($trcAddress['wif']) ? $trcAddress['wif'] : '';
+            $data['trc_hexaddress'] = isset($trcAddress['hexAddress']) ? $trcAddress['hexAddress'] : '';
+            $data['trc_address'] = isset($trcAddress['address']) ? $trcAddress['address'] : '';
+        } else {
             $this->error = 2201;
             return false;
         }
 
         // 生erc2.0钱包地址
         $ercAddress = UsdtWalletService::make()->getErcAddress();
-        if($trcAddress){
-            $data['erc_wif'] = isset($ercAddress['wif'])? $ercAddress['wif'] : '';
-            $data['erc_hexaddress'] = isset($ercAddress['hexAddress'])? $ercAddress['hexAddress'] : '';
-            $data['erc_address'] = isset($ercAddress['address'])? $ercAddress['address'] : '';
-        }else{
+        if ($trcAddress) {
+            $data['erc_wif'] = isset($ercAddress['wif']) ? $ercAddress['wif'] : '';
+            $data['erc_hexaddress'] = isset($ercAddress['hexAddress']) ? $ercAddress['hexAddress'] : '';
+            $data['erc_address'] = isset($ercAddress['address']) ? $ercAddress['address'] : '';
+        } else {
             $this->error = 2202;
             return false;
         }
 
-        if($this->model->insert($data)){
+        if ($id = $this->model->edit($data)) {
+            MemberSettingService::make()->getInfo($id);
             return true;
         }
 
@@ -139,9 +156,9 @@ class MemberService extends BaseService
      */
     public function login($params)
     {
-        $username = isset($params['username'])? $params['username'] : '';
-        $password = isset($params['password'])? $params['password'] : '';
-        if(empty($username) || empty($password)){
+        $username = isset($params['username']) ? $params['username'] : '';
+        $password = isset($params['password']) ? $params['password'] : '';
+        if (empty($username) || empty($password)) {
             $this->error = 1013;
             return false;
         }
@@ -192,26 +209,26 @@ class MemberService extends BaseService
     public function auth($userId, $params)
     {
         $data = [
-            'idcard'=> isset($params['idcard'])? $params['idcard'] : '',
-            'realname'=> isset($params['realname'])? $params['realname'] : '',
+            'idcard' => isset($params['idcard']) ? $params['idcard'] : '',
+            'realname' => isset($params['realname']) ? $params['realname'] : '',
         ];
 
-        if(isset($params['idcard_front_img']) && strpos($params['idcard_front_img'],'http')===false){
+        if (isset($params['idcard_front_img']) && strpos($params['idcard_front_img'], 'http') === false) {
             $data['idcard_front_img'] = $params['idcard_front_img'];
         }
 
-        if(isset($params['idcard_back_img']) && strpos($params['idcard_back_img'],'http')===false){
+        if (isset($params['idcard_back_img']) && strpos($params['idcard_back_img'], 'http') === false) {
             $data['idcard_back_img'] = $params['idcard_back_img'];
         }
 
         $info = $this->getInfo($userId);
-        $idcardCheck = isset($info['idcard_check'])? $info['idcard_check'] : 0;
-        if($idcardCheck == 1){
+        $idcardCheck = isset($info['idcard_check']) ? $info['idcard_check'] : 0;
+        if ($idcardCheck == 1) {
             $this->error = '2011';
             return false;
         }
 
-        return $this->model->where(['id'=> $userId])->update($data);
+        return $this->model->where(['id' => $userId])->update($data);
     }
 
     /**
@@ -222,7 +239,7 @@ class MemberService extends BaseService
      */
     public function getWallet($address, $type = 'trc')
     {
-        return $this->model->where([$type.'_address'=> $address])->select(['id',$type.'_address',$type.'_hexaddress',$type.'_wif'])->first();
+        return $this->model->where([$type . '_address' => $address])->select(['id', $type . '_address', $type . '_hexaddress', $type . '_wif'])->first();
     }
 
     /**
@@ -231,23 +248,114 @@ class MemberService extends BaseService
      * @param int $pageSize
      * @return array|mixed
      */
-    public function getCatchMember($page=1, $pageSize=500)
+    public function getCatchMember($page = 1, $pageSize = 500)
     {
         $cacheKey = "caches:wallet:members:{$page}_{$pageSize}";
-        $datas =  RedisService::get($cacheKey);
-        if($datas){
+        $datas = RedisService::get($cacheKey);
+        if ($datas) {
             return $datas;
         }
 
-        $datas = $this->model->where(['mark'=>1])
-            ->select(['id','trc_address','usdt_num'])
-            ->paginate($pageSize>0? $pageSize : 9999999);
-        $datas = $datas? $datas->toArray() :[];
-        $datas = isset($datas['data'])? $datas['data'] : [];
-        if($datas){
+        $datas = $this->model->where(['mark' => 1])
+            ->select(['id', 'trc_address', 'usdt_num'])
+            ->paginate($pageSize > 0 ? $pageSize : 9999999);
+        $datas = $datas ? $datas->toArray() : [];
+        $datas = isset($datas['data']) ? $datas['data'] : [];
+        if ($datas) {
             RedisService::set($cacheKey, $datas, rand(120, 600));
         }
 
         return $datas;
     }
+
+    /**
+     * 匹配承兑商
+     * @param $num 交易数量
+     * @param int $tradeType 交易类型:1-购买,2-出售
+     */
+    public function getTradeMember($num, $tradeType = 1, $userId=0)
+    {
+        $data = $this->model->from('member as m')
+            ->leftJoin('member_setting as ms', 'ms.user_id', '=', 'm.id')
+            ->where(['m.status' => 1,'m.user_type'=>2, 'm.mark' => 1])
+            ->where('m.usdt_num', '>=', $num)
+            ->where(function($query)use($userId){
+                if($userId){
+                    $query->whereNotIn('m.id', [$userId]);
+                }
+            })
+            ->where(function ($query) use ($tradeType) {
+                $time = time();
+                // 买单
+                if ($tradeType == 1) {
+                    $query->whereRaw("(buy_online = 1 and buy_online_time>{$time}) or buy_online is null");
+                } // 卖单
+                else {
+                    $query->whereRaw("((sell_online = 1 and sell_online_time>{$time}) or sell_online is null) and day_sell_quota > day_sell_total");
+                }
+            })
+            ->select(['m.id','m.usdt_num','m.username','m.credit'])
+            ->orderBy("credit",'desc')
+            ->orderBy(DB::raw("rand()"))
+            ->first();
+
+        $data = $data? $data->toArray() : [];
+        return $data;
+    }
+
+    /**
+     * 生成普通参数二维码
+     * @param $str 参数
+     * @param bool $refresh 是否重新生成
+     * @return bool
+     */
+    public function makeQrcode($str, $refresh = false, $size = 4, $margin=2, $level=2)
+    {
+        $qrFile = '/images/qrcode/';
+        if (!is_dir('/uploads'.$qrFile)) {
+            @mkdir('./uploads' . $qrFile, 0755, true);
+        }
+
+        $qrFile = $qrFile . 'C_' . strtoupper(md5($str . '_' . $size.$margin.$level)) . '.png';
+        $cacheKey = "caches:qrcodes:member_".md5($str);
+        if(RedisService::get($cacheKey) && is_file('/uploads'.$qrFile) && !$refresh){
+            //return $qrFile;
+        }
+        QRcode::png($str, './uploads' . $qrFile, $level, $size, $margin);
+        if(!file_exists('./uploads'.$qrFile)){
+            return false;
+        }
+        RedisService::set($cacheKey, ['str'=> $str, 'qrcode'=> $qrFile,'date'=> date('Y-m-d H:i:s')], 7*24 * 3600);
+        return $qrFile;
+    }
+
+    /**
+     * 获取钱包归集用户列表
+     * @param float $minUsdt
+     * @param int $page
+     * @param int $pageSize
+     * @return array|mixed
+     */
+    public function getTriggerAddressList($minUsdt=0.2, $page=1, $pageSize = 200)
+    {
+        $cacheKey = "caches:wallet:triggers:{$page}_{$pageSize}";
+        $datas = RedisService::get($cacheKey);
+        if ($datas) {
+            return $datas;
+        }
+
+        $datas = $this->model->where(['mark'=>1])
+            ->where('trc_usdt','>=', $minUsdt)
+            ->select(['id','trc_usdt','trc_address','trc_wif','trc_hexaddress','erc_address','erc_wif','erc_hexaddress'])
+            ->orderBy('trc_usdt')
+            ->paginate($pageSize > 0 ? $pageSize : 9999999);
+
+        $datas = $datas ? $datas->toArray() : [];
+        $datas = isset($datas['data']) ? $datas['data'] : [];
+        if ($datas) {
+            RedisService::set($cacheKey, $datas, rand(10, 30));
+        }
+
+        return $datas;
+    }
 }

+ 1 - 1
app/Services/BaseService.php

@@ -141,7 +141,7 @@ class BaseService
         $query = $this->model->where($map)->where(function($query) use($param){
             $businessId = isset($param['bsid'])? intval($param['bsid']) : 0;
             if($businessId>0){
-                $query->where(['user_id'=> $businessId])->orWhere(['business_id'=> $businessId]);
+                $query->where(['business_id'=> $businessId]);
             }
         })->when($sort, function ($query, $sort) {
             foreach ($sort as $v) {

+ 1 - 1
app/Services/Common/MemberService.php

@@ -41,7 +41,7 @@ class MemberService extends BaseService
      */
     public function getInfo($where, array $field=[])
     {
-        $field = $field? $field : ['id','username','realname','nickname','openid','idcard','trc_address','erc_address','source','idcard_check','idcard_front_img','idcard_back_img','safe_level','user_type','member_level','usdt_num','user_type','status','credit','avatar'];
+        $field = $field? $field : ['id','username','realname','nickname','openid','idcard','trc_address','erc_address','source','idcard_check','idcard_front_img','idcard_back_img','idcard_hand_img','safe_level','user_type','member_level','usdt_num','user_type','status','credit','avatar'];
         if(is_array($where)){
             $info = $this->model->where($where)->select($field)->first();
         }else{

+ 0 - 1
app/Services/Common/MemberSettingService.php

@@ -155,7 +155,6 @@ class MemberSettingService extends BaseService
             $data['day_sell_quota'] = floatval($params['day_sell_quota']);
         }
 
-        var_dump($data);
         if($data){
             return $this->model->where(['user_id'=> $userId])->update($data);
         }else{

+ 402 - 11
app/Services/Common/TradeOrderService.php

@@ -11,8 +11,12 @@
 
 namespace App\Services\Common;
 
+use App\Models\CapitalLogModel;
+use App\Models\MemberModel;
 use App\Models\TradeOrderModel;
+use App\Services\Api\MemberPaymentService;
 use App\Services\BaseService;
+use App\Services\ConfigService;
 
 /**
  * 用户交易订单-服务类
@@ -32,6 +36,8 @@ class TradeOrderService extends BaseService
     public function __construct()
     {
         $this->model = new TradeOrderModel();
+        $this->memberModel = new MemberModel();
+        $this->capitalModel = new CapitalLogModel();
     }
 
     /**
@@ -47,19 +53,91 @@ class TradeOrderService extends BaseService
     }
 
     /**
+     * 订单列表
+     * @param $params
+     * @param int $pageSize
+     * @return array
+     */
+    public function getDataList($params, $pageSize = 15)
+    {
+        $list = $this->model->from('trade_order as a')
+            ->leftJoin('member as b', 'b.id', '=', 'a.user_id')
+            ->where(function ($query) use ($params) {
+                $query->where(['a.mark' => 1])->where('a.status', '>', 0);
+
+                $orderNo = isset($params['order_no']) && $params['order_no'] ? trim($params['order_no']) : '';
+                if ($orderNo) {
+                    $query->where('a.order_no', 'like', "%{$orderNo}%");
+                }
+
+                $type = isset($params['type']) ? intval($params['type']) : 0;
+                if ($type > 0) {
+                    $query->where(['a.type' => $type]);
+                }
+
+                // 日期
+                $date = isset($params['date']) ? $params['date'] : '';
+                if ($date) {
+                }
+
+                $exceptionStatus = isset($params['exception_status']) ? intval($params['exception_status']) : 0;
+                if ($exceptionStatus > 0) {
+                    $query->where(['a.exception_status' => $exceptionStatus]);
+                }
+
+                $userId = isset($params['user_id']) ? $params['user_id'] : 0;
+                if ($userId > 0) {
+                    $query->where('a.user_id', $userId);
+                }
+
+                $businessId = isset($params['business_id']) ? $params['business_id'] : 0;
+                if ($businessId > 0) {
+                    $query->where('a.business_id', $businessId);
+                }
+
+            })
+            ->select(['a.*', 'b.username'])
+            ->paginate($pageSize > 0 ? $pageSize : 9999999);
+        $list = $list ? $list->toArray() : [];
+        if ($list) {
+            $overTime = ConfigService::make()->getConfigByCode('trade_order_overtime');
+            $overTime = $overTime ? $overTime : 0;
+            foreach ($list['data'] as &$item) {
+                $item['idcardData'] = $item['idcard_data'] ? json_decode($item['idcard_data'], true) : [];
+                $item['paymentData'] = $item['payment_data'] ? json_decode($item['payment_data'], true) : [];
+                $item['create_time_text'] = $item['create_time'] ? datetime($item['create_time'], 'Y-m-d H:i') : '';
+                $item['time_text'] = $item['create_time'] ? datetime($item['create_time'], 'H:i') : '';
+                $item['pay_time_text'] = $item['pay_time'] ? datetime($item['pay_time'], 'Y-m-d H:i') : '';
+                $item['username_text'] = $item['username'] ? format_account($item['username']) : '';
+
+                $overTime = max(0, intval($item['create_time']) + $overTime * 60 - time());
+                $item['overtime_text'] = in_array($item['status'], [1, 2]) && $overTime ? date('H:i', $overTime) : '';
+            }
+        }
+
+
+        return [
+            'pageSize' => $pageSize,
+            'total' => isset($list['total']) ? $list['total'] : 0,
+            'list' => isset($list['data']) ? $list['data'] : []
+        ];
+    }
+
+    /**
      * 成交交易笔数
      * @param int $type 类型:1-买单,2-卖单
      * @param int $bsid 承兑商用户ID
      * @param int $status 状态:4-成交
      * @return mixed
      */
-    public function getCompleteCount($type = 1, $bsid=0, $status = 4)
+    public function getCompleteCount($type = 1, $bsid = 0, $status = 4)
     {
-        return (int)$this->model->where(['type' => $type, 'status' => $status, 'mark' => 1])->where(function ($query) use ($bsid) {
-            if ($bsid > 0) {
-                $query->where('user_ids','=', $bsid)->orWhere('business_id','=', $bsid);
-            }
-        })->count('id');
+        return (int)$this->model->where(['type' => $type, 'status' => $status, 'mark' => 1])
+            ->where(function ($query) use ($bsid) {
+                if ($bsid > 0) {
+                    $query->where('business_id', '=', $bsid);
+                }
+            })->count('id');
     }
 
     /**
@@ -70,18 +148,39 @@ class TradeOrderService extends BaseService
      * @param string $field 统计字段:total-总金额(默认),num-交易USDT数量
      * @return mixed
      */
-    public function getCompleteTotal($type = 1, $bsid=0, $status = 4, $field = 'total')
+    public function getCompleteTotal($type = 1, $bsid = 0, $status = 4, $field = 'total')
     {
+
         $total = $this->model->where(['type' => $type, 'status' => $status, 'mark' => 1])
             ->where(function ($query) use ($bsid) {
                 if ($bsid > 0) {
-                    $query->where('user_id','=', $bsid)->orWhere('business_id','=', $bsid);
+                    $query->where('business_id', '=', $bsid);
                 }
             })->sum($field);
         return moneyFormat($total, 2);
     }
 
     /**
+     * 今日成交交易金额
+     * @param int $type 类型:1-买单,2-卖单
+     * @param int $bsid 承兑商用户ID
+     * @param int $status 状态:4-成交
+     * @param string $field 统计字段:total-总金额(默认),num-交易USDT数量
+     * @return mixed
+     */
+    public function getCompleteTotalByDay($type = 1, $bsid = 0, $status = 4, $field = 'total')
+    {
+        $total = $this->model->where(['type' => $type, 'status' => $status, 'mark' => 1])
+            ->where('pay_time', '>=', strtotime(date('Y-m-d')))
+            ->where(function ($query) use ($bsid) {
+                if ($bsid > 0) {
+                    $query->where('business_id', '=', $bsid);
+                }
+            })->sum($field);
+        return moneyFormat($total, 6);
+    }
+
+    /**
      * 获取某个时间段的买卖交易量比
      * @param int $type 状态类型:1-成交的
      * @param int $bsid 承兑商用户ID
@@ -97,7 +196,7 @@ class TradeOrderService extends BaseService
         $buyCount = $this->model->where(['type' => 1])->where($where)
             ->where(function ($query) use ($bsid) {
                 if ($bsid > 0) {
-                    $query->where('user_id','=', $bsid)->orWhere('business_id','=', $bsid);
+                    $query->where('business_id', '=', $bsid);
                 }
             })
             ->where('create_time', '>=', time() - $time * 60)
@@ -105,13 +204,305 @@ class TradeOrderService extends BaseService
         $sellCount = $this->model->where(['type' => 2])->where($where)
             ->where(function ($query) use ($bsid) {
                 if ($bsid > 0) {
-                    $query->where('user_id','=', $bsid)->orWhere('business_id','=', $bsid);
+                    $query->where('business_id', '=', $bsid);
                 }
             })
             ->where('create_time', '>=', time() - $time * 60)
             ->count('id');
         $rate = ($buyCount || $sellCount) > 0 ? moneyFormat($buyCount / ($buyCount + $sellCount)) * 100 : 0;
 
-        return ['buy' => $buyCount, 'sell' => $sellCount, 'buy_rate' => $rate, 'sell_rate' => ($sellCount>0? 100 - $rate : 0)];
+        return ['buy' => $buyCount, 'sell' => $sellCount, 'buy_rate' => $rate, 'sell_rate' => ($sellCount > 0 ? 100 - $rate : 0)];
+    }
+
+    /**
+     * 获取未支付或处理的订单数
+     * @param $userId
+     * @param int $type
+     * @return mixed
+     */
+    public function checkOrderNoCatch($userId, $type = 1)
+    {
+        return $this->model->where(['user_id' => $userId, 'type' => $type, 'mark' => 1])->whereIn('status', [1, 2])->count('id');
+    }
+
+    /**
+     * 客户买入
+     * @param $userId
+     * @param $params
+     * @return false|int|number
+     */
+    public function buy($userId, $params)
+    {
+        $num = isset($params['num']) ? floatval($params['num']) : 0;
+        $numType = isset($params['num_type']) ? intval($params['num_type']) : 1;
+        if ($userId <= 0) {
+            $this->error = '1013';
+            return false;
+        }
+
+        // 验证参数
+        $config = ConfigService::make()->getConfigOptionByGroup(5);
+        $tradeOpen = isset($config['trade_usdt_open']) ? $config['trade_usdt_open'] : 0;
+        $tradeMinNum = isset($config['trade_min_num']) ? $config['trade_min_num'] : 0;
+        $tradeMaxNum = isset($config['trade_max_num']) ? $config['trade_max_num'] : 0;
+        $trademinMoney = isset($config['trade_min_money']) ? $config['trade_min_money'] : 0;
+        $tradeMaxMoney = isset($config['trade_max_money']) ? $config['trade_max_money'] : 0;
+        $tradePrice = isset($config['usdt_buy_price']) ? $config['usdt_buy_price'] : 0;
+        $tradeLimitNum = isset($config['trade_no_catch']) ? $config['trade_no_catch'] : 0;
+
+        // 是否开启交易
+        if ($tradeOpen != 1) {
+            $this->error = '1013';
+            return false;
+        }
+
+        if ($tradePrice <= 0) {
+            $this->error = '3002';
+            return false;
+        }
+
+        // 验证数量或金额
+        $total = 0;
+        if ($numType == 1) {
+            if ($num < $tradeMinNum || $num > $tradeMaxNum) {
+                $this->error = '3003';
+                return false;
+            }
+
+            $total = moneyFormat($num * $tradePrice, 6);
+        } else {
+            if ($num < $trademinMoney || $num > $tradeMaxMoney) {
+                $this->error = '3003';
+                return false;
+            }
+            $total = moneyFormat($num, 6);
+            $num = moneyFormat($num * $tradePrice, 6);
+        }
+
+        // 用户信息
+        $userInfo = MemberService::make()->getInfo($userId);
+        $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
+        if ($status != 1) {
+            $this->error = '2009';
+            return false;
+        }
+
+        // 匹配交易商家
+        $businessInfo = \App\Services\Api\MemberService::make()->getTradeMember($num, 1, $userId);
+        if (empty($businessInfo)) {
+            $this->error = '3004';
+            return false;
+        }
+
+        $noCatchOrder = $this->checkOrderNoCatch($userId, 1);
+        if ($tradeLimitNum > 0 && $noCatchOrder >= $tradeLimitNum) {
+            $this->error = lang(3005, ['num' => $tradeLimitNum]);
+            return false;
+        }
+
+        $data = [
+            'user_id' => $userId,
+            'business_id' => isset($businessInfo['id']) ? $businessInfo['id'] : 0,
+            'order_no' => get_order_num('OT'),
+            'type' => 1,
+            'pay_type' => isset($params['pay_type']) ? floatval($params['pay_type']) : 1,
+            'price' => $tradePrice,
+            'num' => $num,
+            'total' => $total,
+            'create_time' => time(),
+            'update_time' => time(),
+            'status' => 1,
+            'mark' => 1,
+        ];
+
+        return $this->model->edit($data);
+    }
+
+
+    /**
+     * 客户卖出
+     * @param $userId
+     * @param $params
+     * @return false|int|number
+     */
+    public function sell($userId, $params)
+    {
+        $num = isset($params['num']) ? floatval($params['num']) : 0;
+        if ($userId <= 0) {
+            $this->error = '1013';
+            return false;
+        }
+
+        // 验证参数
+        $config = ConfigService::make()->getConfigOptionByGroup(5);
+        $tradeOpen = isset($config['trade_usdt_open']) ? $config['trade_usdt_open'] : 0;
+        $tradeMinNum = isset($config['trade_min']) ? $config['trade_min'] : 0;
+        $tradeMaxNum = isset($config['trade_max']) ? $config['trade_max'] : 0;
+        $tradePrice = isset($config['usdt_sell_price']) ? $config['usdt_sell_price'] : 0;
+        $tradeLimitNum = isset($config['trade_no_catch']) ? $config['trade_no_catch'] : 0;
+
+        // 是否开启交易
+        if ($tradeOpen != 1) {
+            $this->error = '1013';
+            return false;
+        }
+
+        if ($tradePrice <= 0) {
+            $this->error = '3002';
+            return false;
+        }
+
+        // 验证数量或金额
+        $total = moneyFormat($num * $tradePrice, 6);
+        if ($num < $tradeMinNum || ($tradeMaxNum && $num > $tradeMaxNum)) {
+            $this->error = '3003';
+            return false;
+        }
+
+        // 用户信息
+        $userInfo = MemberService::make()->getInfo($userId);
+        $status = isset($userInfo['status']) ? $userInfo['status'] : 0;
+        $usdtNum = isset($userInfo['usdt_num']) ? $userInfo['usdt_num'] : 0;
+        if ($status != 1) {
+            $this->error = '2009';
+            return false;
+        }
+
+        if ($usdtNum < $num) {
+            $this->error = '3011';
+            return false;
+        }
+
+        // 匹配交易商家
+        $businessInfo = \App\Services\Api\MemberService::make()->getTradeMember($num, 2, $userId);
+        if (empty($businessInfo)) {
+            $this->error = '3004';
+            return false;
+        }
+
+        // 未处理订单
+        $noCatchOrder = $this->checkOrderNoCatch($userId, 2);
+        if ($tradeLimitNum > 0 && $noCatchOrder >= $tradeLimitNum) {
+            $this->error = lang(3005, ['num' => $tradeLimitNum]);
+            return false;
+        }
+
+        // 收款方式
+        $paymentId = isset($params['payment_id']) ? $params['payment_id'] : 0;
+        $paymentInfo = MemberPaymentService::make()->getInfo($paymentId);
+        if (empty($paymentInfo)) {
+            $this->error = '3010';
+            return false;
+        }
+
+        $paymentData = [
+            'payment_id' => $paymentInfo['id'],
+            'type' => $paymentInfo['type'],
+            'logo' => $paymentInfo['logo'] ? get_image_url($paymentInfo['logo']) : '',
+            'real_name' => $paymentInfo['real_name'],
+            'bank_name' => $paymentInfo['bank_name'],
+            'bank_card' => $paymentInfo['bank_card'],
+            'branch_name' => $paymentInfo['branch_name'],
+            'qrcode' => $paymentInfo['qrcode'] ? get_image_url($paymentInfo['qrcode']) : '',
+            'account' => $paymentInfo['account'],
+        ];
+
+        $data = [
+            'user_id' => $userId,
+            'business_id' => isset($businessInfo['id']) ? $businessInfo['id'] : 0,
+            'order_no' => get_order_num('OT'),
+            'type' => 2,
+            'pay_type' => isset($params['pay_type']) ? floatval($params['pay_type']) : 1,
+            'price' => $tradePrice,
+            'num' => $num,
+            'payment_id' => $paymentId,
+            'payment_data' => json_encode($paymentData, 256),
+            'total' => $total,
+            'create_time' => time(),
+            'status' => 1,
+            'mark' => 1,
+        ];
+
+        $this->model->startTrans();
+        if (!$order = $this->model->edit($data)) {
+            $this->error = '3012';
+            $this->model->rollBack();
+            return false;
+        }
+
+        // 扣除币
+        if (!$this->memberModel->where(['id' => $userId])->decrement('usdt_num', $num)) {
+            $this->error = '3013';
+            $this->model->rollBack();
+            return false;
+        }
+
+        // 账户明细
+        $data = [
+            'order_no' => $data['order_no'],
+            'user_id' => $userId,
+            'type' => 1,
+            'change_type' => 2,
+            'num' => $num,
+            'total' => $total,
+            'create_time' => time(),
+            'remark' => '',
+            'status' => 1,
+            'mark' => 1,
+        ];
+
+        if (!$this->capitalModel->edit($data)) {
+            $this->error = '3014';
+            $this->model->rollBack();
+            return false;
+        }
+
+        $this->model->commit();
+        return $order;
+    }
+
+
+    public function catchInvalidOrder()
+    {
+        $overtime = ConfigService::make()->getConfigByCode('trade_order_overtime');
+        $cancelTime = ConfigService::make()->getConfigByCode('trade_order_cancel');
+        $catchNum = ConfigService::make()->getConfigByCode('trade_order_catch_num');
+        $catchNum = $catchNum>0? $catchNum : 200;
+
+        // 处理超时订单
+        if ($overtime > 0) {
+            $this->model->where(['mark' => 1])
+                ->where('status', '<=', 2)
+                ->where('create_time', '<=', time() - $overtime * 60)
+                ->update(['status' => 7, 'catch_at' => time()]);
+        }
+
+
+        if ($cancelTime <= 0) {
+            $this->error = '1023';
+            return false;
+        }
+
+        $this->model->where(function ($query) use ($cancelTime) {
+            // 已更新为超时的订单
+            $query->where(['mark' => 1, 'status' => 7])
+                ->where('catch_at', '<=', time() - $cancelTime * 60);
+        })
+            ->orWhere(function ($query) use ($cancelTime, $overtime) {
+                $query->where('mark', '=', 1)
+                    ->where('status', '<=', 2)
+                    ->where('create_time', '<=', time() - ($cancelTime + $overtime) * 60);
+            })
+            ->select(['id', 'user_id', 'business_id', 'type', 'num'])
+            ->get()
+            ->limit(500)
+            ->each(function ($item, $k) {
+                //
+                $type = isset($item['type'])? $item['type'] : 0;
+                if($type == 2){
+
+                }
+            });
+
     }
 }

+ 6 - 0
app/Services/Common/UserService.php

@@ -158,6 +158,9 @@ class UserService extends BaseService
             'username'=> $username,
             'realname'=> isset($data['realname'])? $data['realname'] : '',
             'gender'=> isset($data['gender'])? $data['gender'] : 0,
+            'user_type'=> 2,
+            'mark'=> 1,
+            'status'=> 1,
         ];
 
         // 生成trc2.0钱包地址
@@ -197,6 +200,9 @@ class UserService extends BaseService
 
             // 更新绑定会员账号
             $this->model->where(['id'=> $adminId])->update(['user_id'=> $userId]);
+
+            // 用户交易配置
+            MemberSettingService::make()->getInfo($userId);
         }
 
 

+ 282 - 79
app/Services/UsdtWalletService.php

@@ -30,6 +30,7 @@ use IEXBase\TronAPI\Tron;
 use Tron\Api;
 use Tron\TRC20;
 use Tron\TRX;
+use Web3\Personal;
 use Web3\Web3;
 use Web3p\EthereumUtil\Util;
 
@@ -44,7 +45,7 @@ class UsdtWalletService extends BaseService
     protected $config = [];
     protected $apiUrls = [
         'usdt_trx2_transfer_log' => '/v1/accounts/%s/transactions/trc20?limit=%s&only_to=%s&only_from=%s&only_confirmed=true&contract_address=TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'
-     ];
+    ];
 
     /**
      * 构造函数
@@ -74,7 +75,7 @@ class UsdtWalletService extends BaseService
      * 获取TRC2.0钱包地址
      * @throws \Tron\Exceptions\TronErrorException
      */
-    public function getTrxAddress()
+    public function getTrxAddress1()
     {
         $api = new Api(new Client(['base_uri' => $this->config['tron_api_url']]));
 
@@ -85,6 +86,18 @@ class UsdtWalletService extends BaseService
     }
 
     /**
+     * 获取TRC2.0钱包地址
+     * @throws \Tron\Exceptions\TronErrorException
+     */
+    public function getTrxAddress($userId = 0)
+    {
+        $api = new Api(new Client(['base_uri' => $this->config['tron_api_url']]));
+
+        $trxWallet = new TRX($api);
+        $addressData = $trxWallet->generateAddress();
+    }
+
+    /**
      * trx 转账
      * @param $from 转账账户
      * @param $to 进账账户
@@ -92,7 +105,7 @@ class UsdtWalletService extends BaseService
      * @throws \Tron\Exceptions\TransactionException
      * @throws \Tron\Exceptions\TronErrorException
      */
-    public function trxTransfer($from, $to, $amount)
+    public function trxTransfer($to, $amount)
     {
         if ($amount <= 0) {
             $this->error = '2205';
@@ -105,23 +118,28 @@ class UsdtWalletService extends BaseService
             return false;
         }
 
-        $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']];
-        $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'],'headers'=> $headers]));
+        $headers = ["TRON-PRO-API-KEY" => $this->config['tron_api_key']];
+        $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'], 'headers' => $headers]));
         $trxWallet = new TRX($api);
 
         // 获取钱包参数
         try {
-            $fromData = MemberService::make()->getWallet($from, 'trc');
-            $privateKey = isset($fromData['trc_wif']) ? $fromData['trc_wif'] : '';
-            $hexAddress = isset($fromData['trc_hexaddress']) ? $fromData['trc_hexaddress'] : '';
-            if (empty($privateKey) || empty($hexAddress)) {
+            $otcAddress = ConfigService::make()->getConfigByCode('trc_address');
+            $otcAddressPrivate = ConfigService::make()->getConfigByCode('trc_private_key');
+            if (empty($otcAddress) || empty($otcAddressPrivate)) {
                 $this->error = '2203';
                 return false;
             }
+
             $tron = new Tron();
+            // 获取平台钱包hex
+            $tron->setAddress($otcAddress);
+            $otcAddress = $tron->getAddress();
+
+
             $tron->setAddress($to);
             $toAddress = $tron->getAddress();
-            $from = new \Tron\Address($from, $privateKey, $hexAddress);
+            $from = new \Tron\Address($otcAddress['base58'], $otcAddressPrivate, $otcAddress['hex']);
             $to = new \Tron\Address($toAddress['base58'], '', $toAddress['hex']);
             $result = $trxWallet->transfer($from, $to, $amount);
 
@@ -141,7 +159,7 @@ class UsdtWalletService extends BaseService
      * @throws \Tron\Exceptions\TransactionException
      * @throws \Tron\Exceptions\TronErrorException
      */
-    public function usdtTrcTransfer($from, $to, $amount)
+    public function usdtTrcTransfer($to, $amount)
     {
         if ($amount <= 0) {
             $this->error = '2205';
@@ -153,24 +171,29 @@ class UsdtWalletService extends BaseService
             return false;
         }
 
-        $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']];
-        $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'],'headers'=> $headers]));
+        $headers = ["TRON-PRO-API-KEY" => $this->config['tron_api_key']];
+        $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'], 'headers' => $headers]));
         $trxWallet = new TRC20($api, ['contract_address' => $this->config['tron_contract_address'], 'decimals' => 6]);
 
         // 获取钱包参数
         try {
-            $fromData = MemberService::make()->getWallet($from, 'trc');
-            $privateKey = isset($fromData['trc_wif']) ? $fromData['trc_wif'] : '';
-            $hexAddress = isset($fromData['trc_hexaddress']) ? $fromData['trc_hexaddress'] : '';
-            if (empty($privateKey) || empty($hexAddress)) {
+
+            $otcAddress = ConfigService::make()->getConfigByCode('trc_address');
+            $otcAddressPrivate = ConfigService::make()->getConfigByCode('trc_private_key');
+            if (empty($otcAddress) || empty($otcAddressPrivate)) {
                 $this->error = '2203';
                 return false;
             }
 
             $tron = new Tron();
+            // 获取平台钱包hex
+            $tron->setAddress($otcAddress);
+            $otcAddress = $tron->getAddress();
+
+            // 获取收款钱包hex
             $tron->setAddress($to);
             $toAddress = $tron->getAddress();
-            $from = new \Tron\Address($from, $privateKey, $hexAddress);
+            $from = new \Tron\Address($otcAddress['base58'], $otcAddressPrivate, $otcAddress['hex']);
             $to = new \Tron\Address($toAddress['base58'], '', $toAddress['hex']);
             $result = $trxWallet->transfer($from, $to, $amount);
             return $result;
@@ -183,6 +206,141 @@ class UsdtWalletService extends BaseService
     }
 
     /**
+     * usdt-trc2.0 归集
+     * @throws \Tron\Exceptions\TransactionException
+     * @throws \Tron\Exceptions\TronErrorException
+     */
+    public function usdtTrcTrigger($force = false)
+    {
+
+        if (empty($this->config['tron_api_url'])) {
+            $this->error = '2206';
+            return false;
+        }
+
+        $headers = ["TRON-PRO-API-KEY" => $this->config['tron_api_key']];
+        $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'], 'headers' => $headers]));
+        $trcWallet = new TRC20($api, ['contract_address' => $this->config['tron_contract_address'], 'decimals' => 6]);
+        $trxWallet = new TRX($api, ['contract_address' => $this->config['tron_contract_address'], 'decimals' => 6]);
+
+        // 获取钱包参数
+        try {
+
+            $otcAddress = ConfigService::make()->getConfigByCode('trc_address');
+            $otcAddressPrivate = ConfigService::make()->getConfigByCode('trc_private_key');
+            $triggerMin = ConfigService::make()->getConfigByCode('trade_trigger_min');
+            $triggerTime = ConfigService::make()->getConfigByCode('trade_trigger_time');
+            $triggerFree = ConfigService::make()->getConfigByCode('trade_trigger_free');
+            $triggerFree = $triggerFree > 0 ? $triggerFree : 8;
+            $triggerMin = $triggerMin > 0 ? $triggerMin : 0.1;
+            $triggerTime = $triggerTime > 0 ? $triggerTime * 86400 : 86400;
+            if (empty($otcAddress) || empty($otcAddressPrivate)) {
+                $this->error = '2203';
+                return false;
+            }
+
+            $page = RedisService::get("caches:wallet:transferPage");
+            $page = $page ? $page : 1;
+
+            // 归集时间段为凌晨0点-5点
+            if ((date('H:i') >= '05:00') && !$force) {
+                $this->error = '不在归集时间段';
+                return false;
+            }
+
+            if(RedisService::get("caches:wallet:triggerLock:{$page}")){
+                $this->error = '不要频繁操作,30秒后重试';
+                return false;
+            }
+
+            // 上锁
+            RedisService::set("caches:wallet:triggerLock:{$page}", 1, rand(10, 30));
+            $addrList = MemberService::make()->getTriggerAddressList($triggerMin, $page, 200);
+            var_dump($addrList);
+            if (empty($addrList)) {
+                RedisService::set("caches:wallet:transferPage", 1, 600);
+                $this->error = '1019';
+                return false;
+            }
+
+
+
+            // 平台钱包地址
+            $count = 0;
+            $failedCount = 0;
+            $tron = new Tron();
+            $tron->setAddress($otcAddress);
+            $otcAddress = $tron->getAddress();
+            $otcAddressData = new \Tron\Address($otcAddress['base58'], $otcAddressPrivate, $otcAddress['hex']);
+            $cacheKey = "caches:wallet:trigger:";
+            foreach ($addrList as $v) {
+                try {
+                    // 获取子钱包TRC-USDT余额
+                    $userId = isset($v['user_id']) ? $v['user_id'] : 0;
+                    $address = isset($v['trc_address']) ? $v['trc_address'] : '';
+                    $addressPrivate = isset($v['trc_wif']) ? $v['trc_wif'] : '';
+                    $triggerAddress = new \Tron\Address($address['base58'], $addressPrivate, $address['hex']);
+                    // 可归集的USDT余额
+                    $triggerUsdt = $trcWallet->balance($triggerAddress);
+
+                    // USDT 余额低于归集金额,则不归集
+                    if ($triggerUsdt < $triggerMin) {
+                        $failedCount++;
+                        $error = ['data' => $v, 'usdt' => $triggerUsdt, 'triggerMin' => $triggerMin, 'error' => '用户余额不足归集', 'date' => date('Y-m-d H:i:s')];
+                        RedisService::set($cacheKey . "U_{$userId}:error", $error, 7200);
+                        continue;
+                    }
+
+                    // 获取子钱包TRX余额
+                    $triggerTrx = $trxWallet->balance($triggerAddress);
+
+                    // 获取平台钱包TRX余额
+                    $otcTrxTotal = $trxWallet->balance($otcAddressData);
+
+                    // 如果子钱包和平台钱包TRX余额不足手续费,则不归集
+                    if ($triggerTrx < $triggerFree && $otcTrxTotal < $triggerFree) {
+                        $failedCount++;
+                        $error = ['data' => $v, 'usdt' => $triggerUsdt, 'triggerMin' => $triggerMin,'triggerTrx' => $triggerTrx, 'otcTrx' => $otcTrxTotal, 'error' => '平台钱包手续费不足', 'date' => date('Y-m-d H:i:s')];
+                        RedisService::set($cacheKey . "U_{$userId}:error", $error, 7200);
+                        continue;
+                    }
+
+                    // 如果子钱包TRX不足手续费8个,平台TRX充足则自动充值后下次调用时归集
+                    if ($triggerTrx < $triggerFree) {
+                        $failedCount++;
+                        $this->trxTransfer($otcAddress['base58']);
+                        $error = ['data' => $v, 'usdt' => $triggerUsdt, 'triggerMin' => $triggerMin, 'triggerTrx' => $triggerTrx, 'error' => '归集钱包手续费不足,先充值', 'date' => date('Y-m-d H:i:s')];
+                        RedisService::set($cacheKey . "U_{$userId}:catch", $error, 7200);
+                        continue;
+                    }
+
+                    // 满足归集条件处理
+                    $result = $trxWallet->transfer($triggerAddress, $otcAddressData, $triggerUsdt);
+                    RedisService::set($cacheKey . "U_{$userId}:result", ['data'=> $v,'result'=>$result,'msg'=>'归集已提交','date' => date('Y-m-d H:i:s')], 7200);
+                    $count++;
+                } catch (\Exception $exception) {
+                    $failedCount++;
+                    RedisService::set($cacheKey . "U_{$userId}:exception", ['data'=> $v,'msg'=>$exception->getMessage(),'date' => date('Y-m-d H:i:s')], 7200);
+                }
+
+            }
+
+            // 已经归集过
+            RedisService::set("caches:wallet:transferPage", $page + 1, 600);
+            if ($count > 0) {
+                return ['success' => $count, 'fail' => $failedCount];
+            } else {
+                $this->error = 1021;
+                return false;
+            }
+        } catch (\Exception $exception) {
+            $this->error = $exception->getMessage();
+            return false;
+        }
+    }
+
+
+    /**
      * 监听USDT-TRC2.0转账记录并进账
      * @param $userId 用户ID
      * @param $address 用户钱包地址
@@ -190,17 +348,17 @@ class UsdtWalletService extends BaseService
      * @param int $limit 转账记录数,最新的
      * @return array|false
      */
-    public function getTrc20RechargeLog($userId, $address, $coinType= 1, $limit = 50)
+    public function getTrc20RechargeLog($userId, $address, $coinType = 1, $limit = 50)
     {
-        if($userId<=0 || empty($address)){
+        if ($userId <= 0 || empty($address)) {
             $this->error = '1013';
             return false;
         }
 
-        $url = sprintf($this->apiUrls['usdt_trx2_transfer_log'], $address, $limit, 'true','false');
-        $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']];
+        $url = sprintf($this->apiUrls['usdt_trx2_transfer_log'], $address, $limit, 'true', 'false');
+        $headers = ["TRON-PRO-API-KEY" => $this->config['tron_api_key']];
         $result = curl_get($this->config['tron_api_url'] . $url, [], $headers, 10);
-        $result = $result? json_decode($result, true) : [];
+        $result = $result ? json_decode($result, true) : [];
         $datas = isset($result['data']) ? $result['data'] : [];
         $status = isset($result['success']) ? $result['success'] : '';
         if ($status != true || empty($datas)) {
@@ -210,31 +368,33 @@ class UsdtWalletService extends BaseService
 
         $logs = [];
         foreach ($datas as $v) {
-            $amount = isset($v['value'])? intval($v['value']) : 0;
-            $amount = moneyFormat($amount/1000000, 6);
-            $time = isset($v['block_timestamp'])? intval($v['block_timestamp']) : 0;
-            $txid = isset($v['transaction_id'])? $v['transaction_id'] : '';
-            if(!CoinLogService::make()->checkExists('txid', $txid) && $time> time() - 6*3600){
-                $balance = $this->memberModel->where(['id'=> $userId])->value('usdt_num');
+            $amount = isset($v['value']) ? intval($v['value']) : 0;
+            $amount = moneyFormat($amount / 1000000, 6);
+            $time = isset($v['block_timestamp']) ? intval($v['block_timestamp']) : 0;
+            $txid = isset($v['transaction_id']) ? $v['transaction_id'] : '';
+            if (!CoinLogService::make()->checkExists('txid', $txid) && $time > time() - 6 * 3600) {
+                $balance = $this->memberModel->where(['id' => $userId])->value('usdt_num');
                 $log = [
-                    'user_id'=> $userId,
-                    'change_type'=> 1,
-                    'coin_type'=> $coinType,
-                    'contact_type'=> 1,
-                    'order_no'=> get_order_num('OT'),
-                    'from_address'=> isset($v['from'])? $v['from'] : '',
-                    'to_address'=> isset($v['to'])? $v['to'] : '',
-                    'txid'=> $txid,
-                    'num'=> $amount,
-                    'balance'=> $balance,
-                    'create_time'=> intval($time/1000),
-                    'status'=> 1,
-                    'mark'=> 1,
+                    'user_id' => $userId,
+                    'change_type' => 1,
+                    'coin_type' => $coinType,
+                    'contact_type' => 1,
+                    'order_no' => get_order_num('OT'),
+                    'from_address' => isset($v['from']) ? $v['from'] : '',
+                    'to_address' => isset($v['to']) ? $v['to'] : '',
+                    'txid' => $txid,
+                    'num' => $amount,
+                    'balance' => $balance,
+                    'create_time' => intval($time / 1000),
+                    'status' => 1,
+                    'mark' => 1,
                 ];
 
-                if($this->memberModel->where(['id'=> $userId])->increment('usdt_num', $amount)){
+                if ($this->memberModel->where(['id' => $userId])->increment('usdt_num', $amount)) {
                     $logs[] = $log;
                     $this->coinModel->insert($log);
+
+                    $this->memberModel->where(['id' => $userId])->increment('trc_usdt', $amount);
                 }
             }
         }
@@ -251,17 +411,17 @@ class UsdtWalletService extends BaseService
      * @param int $limit 转账记录数,最新的
      * @return array|false
      */
-    public function getTrc20TransferLog($userId, $address, $coinType= 1, $limit = 50)
+    public function getTrc20TransferLog($userId, $address, $coinType = 1, $limit = 50)
     {
-        if($userId<=0 || empty($address)){
+        if ($userId <= 0 || empty($address)) {
             $this->error = '1013';
             return false;
         }
 
-        $url = sprintf($this->apiUrls['usdt_trx2_transfer_log'], $address, $limit, 'false','true');
-        $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']];
+        $url = sprintf($this->apiUrls['usdt_trx2_transfer_log'], $address, $limit, 'false', 'true');
+        $headers = ["TRON-PRO-API-KEY" => $this->config['tron_api_key']];
         $result = curl_get($this->config['tron_api_url'] . $url, [], $headers, 10);
-        $result = $result? json_decode($result, true) : [];
+        $result = $result ? json_decode($result, true) : [];
         $datas = isset($result['data']) ? $result['data'] : [];
         $status = isset($result['success']) ? $result['success'] : '';
         if ($status != true || empty($datas)) {
@@ -271,31 +431,33 @@ class UsdtWalletService extends BaseService
 
         $logs = [];
         foreach ($datas as $v) {
-            $amount = isset($v['value'])? intval($v['value']) : 0;
-            $amount = moneyFormat($amount/1000000, 6);
-            $time = isset($v['block_timestamp'])? intval($v['block_timestamp']) : 0;
-            $txid = isset($v['transaction_id'])? $v['transaction_id'] : '';
-            if(!CoinLogService::make()->checkExists('txid', $txid) && $time> time() - 6*3600){
-                $balance = $this->memberModel->where(['id'=> $userId])->value('usdt_num');
+            $amount = isset($v['value']) ? intval($v['value']) : 0;
+            $amount = moneyFormat($amount / 1000000, 6);
+            $time = isset($v['block_timestamp']) ? intval($v['block_timestamp']) : 0;
+            $txid = isset($v['transaction_id']) ? $v['transaction_id'] : '';
+            if (!CoinLogService::make()->checkExists('txid', $txid) && $time > time() - 6 * 3600) {
+                $balance = $this->memberModel->where(['id' => $userId])->value('usdt_num');
                 $log = [
-                    'user_id'=> $userId,
-                    'change_type'=> 2,
-                    'coin_type'=> $coinType,
-                    'contact_type'=> 1,
-                    'order_no'=> get_order_num('OT'),
-                    'from_address'=> isset($v['from'])? $v['from'] : '',
-                    'to_address'=> isset($v['to'])? $v['to'] : '',
-                    'txid'=> $txid,
-                    'num'=> $amount,
-                    'balance'=> $balance,
-                    'create_time'=> intval($time/1000),
-                    'status'=> 1,
-                    'mark'=> 1,
+                    'user_id' => $userId,
+                    'change_type' => 2,
+                    'coin_type' => $coinType,
+                    'contact_type' => 1,
+                    'order_no' => get_order_num('OT'),
+                    'from_address' => isset($v['from']) ? $v['from'] : '',
+                    'to_address' => isset($v['to']) ? $v['to'] : '',
+                    'txid' => $txid,
+                    'num' => $amount,
+                    'balance' => $balance,
+                    'create_time' => intval($time / 1000),
+                    'status' => 1,
+                    'mark' => 1,
                 ];
 
-                if($this->memberModel->where(['id'=> $userId])->decrement('usdt_num', $amount)){
+                if ($this->memberModel->where(['id' => $userId])->decrement('usdt_num', $amount)) {
                     $logs[] = $log;
                     $this->coinModel->insert($log);
+
+                    $this->memberModel->where(['id' => $userId])->decrement('trc_usdt', $amount);
                 }
             }
         }
@@ -307,10 +469,50 @@ class UsdtWalletService extends BaseService
      * @param $address
      * @return false|float|string
      */
+    public function getTrxBalance($address)
+    {
+        $cacheKey = "caches:wallet:balance:{$address}";
+        if (RedisService::get($cacheKey)) {
+            return false;
+        }
+
+        if (empty($address)) {
+            $this->error = '1018';
+            return false;
+        }
+
+        if (empty($this->config['tron_api_url'])) {
+            $this->error = '2206';
+            return false;
+        }
+
+        try {
+            $headers = ["TRON-PRO-API-KEY" => $this->config['tron_api_key']];
+            $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'], 'headers' => $headers]));
+            $trxWallet = new TRX($api, ['contract_address' => $this->config['tron_contract_address'], 'decimals' => 6]);
+
+            $tron = new Tron();
+            $tron->setAddress($address);
+            $address = $tron->getAddress();
+            $address = new \Tron\Address($address['base58'], '', $address['hex']);
+            $result = $trxWallet->balance($address);
+
+            return $result ? floatval($result) : '0.00';
+
+        } catch (\Exception $exception) {
+            $this->error = $exception->getMessage();
+            return false;
+        }
+    }
+
+    /**
+     * @param $address
+     * @return false|float|string
+     */
     public function getUsdtByTrc20($address)
     {
         $cacheKey = "caches:wallet:balance:{$address}";
-        if(RedisService::get($cacheKey)){
+        if (RedisService::get($cacheKey)) {
             return false;
         }
 
@@ -325,8 +527,8 @@ class UsdtWalletService extends BaseService
         }
 
         try {
-            $headers = ["TRON-PRO-API-KEY"=> $this->config['tron_api_key']];
-            $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'],'headers'=> $headers]));
+            $headers = ["TRON-PRO-API-KEY" => $this->config['tron_api_key']];
+            $api = new Api(new Client(['base_uri' => $this->config['tron_api_url'], 'headers' => $headers]));
             $trxWallet = new TRC20($api, ['contract_address' => $this->config['tron_contract_address'], 'decimals' => 6]);
 
             $tron = new Tron();
@@ -335,9 +537,9 @@ class UsdtWalletService extends BaseService
             $address = new \Tron\Address($address['base58'], '', $address['hex']);
             $result = $trxWallet->balance($address);
 
-            return $result? floatval($result) : '0.00';
+            return $result ? floatval($result) : '0.00';
 
-        } catch (\Exception $exception){
+        } catch (\Exception $exception) {
             $this->error = $exception->getMessage();
             return false;
         }
@@ -405,17 +607,18 @@ class UsdtWalletService extends BaseService
 
     public function getWebAddress($label = '1')
     {
-        $web3 = new Web3("https://cloudflare-eth.com");
-        $web3->eth->personal->newAccount($label, function ($err, $account) use (&$newAccount) {
+        $personal = new Personal("https://cloudflare-eth.com");
+        $personal->batch(true);
+        $personal->listAccounts();
+        $personal->newAccount('123456');
+        $personal->provider->execute(function ($err, $data) {
             if ($err !== null) {
-                echo 'Error: ' . $err->getMessage();
+                // do something
                 return;
             }
-            $newAccount = $account;
-            echo 'New account: ' . $account . PHP_EOL;
+            // do something
         });
 
-        var_dump($newAccount);
     }
 
     /**