// +---------------------------------------------------------------------- namespace App\Services\Api; use App\Helpers\Jwt; use App\Models\ActionLogModel; use App\Models\MemberModel; use App\Services\BaseService; use App\Services\Common\ApiService; use App\Services\Common\MemberSettingService; use App\Services\ConfigService; use App\Services\RedisService; use App\Services\UsdtWalletService; use Earnp\GoogleAuthenticator\GoogleAuthenticator; use Illuminate\Support\Facades\DB; use phpQrcode\QRcode; /** * 会员-服务类 * Class MemberService * @package App\Services\Api */ class MemberService extends BaseService { // 静态对象 protected static $instance = null; /** * 构造函数 * @since 2020/11/10 * 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 $where * @param array $field */ public function getInfo($where, array $field = []) { $field = $field ? $field : ['id', 'api_id', 'username', 'realname', 'nickname', 'openid', 'idcard', 'google_secret', 'password', 'trade_password', 'trc_address', 'erc_address', 'erc_hexaddress', 'source', 'idcard_check', 'idcard_front_img', 'idcard_back_img', 'idcard_hand_img', 'bank_front_img', 'bank_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(); } $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['idcard_hand_img'] = $info['idcard_hand_img'] ? get_image_url($info['idcard_hand_img']) : ''; $info['bank_front_img'] = $info['bank_front_img'] ? get_image_url($info['bank_front_img']) : ''; $info['bank_back_img'] = $info['bank_back_img'] ? get_image_url($info['bank_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']); $info['set_trade_password'] = $info['trade_password'] ? 1 : 0; $info['set_trade_password'] = $info['trade_password'] == $info['password'] ? 2 : $info['set_trade_password']; unset($info['password']); unset($info['trade_password']); // 收款二维码 $qrcode = $this->makeQrcode($info['trc_address']); $info['trc_qrcode'] = $qrcode ? get_image_url($qrcode) : ''; $ercQrcode = $this->makeQrcode($info['erc_hexaddress']); $info['erc_qrcode'] = $ercQrcode ? get_image_url($ercQrcode) : ''; } return $info; } /** * 用户注册 * @param $params * @return bool */ public function register($params) { // 检测账号是否存在 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']) : ''; $userType = isset($params['user_type']) ? intval($params['user_type']) : 1; if (!checkPassword($password)) { $this->error = '2007'; return false; } $data = [ 'user_type' => $userType ? $userType : 1, 'username' => $username, 'password' => get_password($password . md5($password . 'otc')), 'trade_password' => get_password($password . md5($password . 'otc')), 'mobile' => isPhone($username) ? $username : '', 'status' => 1, 'mark' => 1, 'create_time' => time(), ]; // 谷歌验证码 $google = GoogleAuthenticator::CreateSecret(); $data['google_secret'] = isset($google['secret']) ? $google['secret'] : ''; // 生成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 { $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 { $this->error = 2202; return false; } if ($id = $this->model->edit($data)) { MemberSettingService::make()->getInfo($id); return true; } $this->error = 2007; return false; } /** * 用户登录 * @param $params * @return array|false */ public function login($params) { $username = isset($params['username']) ? $params['username'] : ''; $password = isset($params['password']) ? $params['password'] : ''; if (empty($username) || empty($password)) { $this->error = 1013; return false; } // 用户验证 $info = $this->model->getOne([['username', '=', $username]]); if (!$info) { $this->error = 2001; return false; } // 密码校验 $password = get_password($password . md5($password . 'otc')); if ($password != $info['password']) { $this->error = 2002; return false; } // 使用状态校验 if ($info['status'] != 1) { $this->error = 2009; return false; } // 承兑商 if ($info['user_type'] == 2) { $this->error = 1024; return false; } // 设置日志标题 ActionLogModel::setTitle("会员登录APP"); ActionLogModel::record($info); // JWT生成token $jwt = new Jwt('jwt_app'); $token = $jwt->getToken($info['id']); RedisService::set("stores:auths:info:{$info['id']}", $info, 5, 10); // 登录 $updateData = ['login_time' => time(),'is_online'=>1,'login_count'=>$info['login_count']+1, 'login_ip' => get_client_ip()]; if (empty($info['google_secret'])) { $google = GoogleAuthenticator::CreateSecret(); $updateData['google_secret'] = isset($google['secret']) ? $google['secret'] : ''; } $this->model->where(['id' => $info['id']])->update($updateData); // 登录数据 return [ 'token' => $token, 'user_id' => $info['id'], 'user_type' => $info['user_type'], ]; } /** * API用户注册 * @param $apiId * @param $params * @return bool * @throws \BitWasp\Bitcoin\Exceptions\RandomBytesFailure * @throws \Tron\Exceptions\TronErrorException */ public function apiRegister($apiId, $params) { // 检测账号是否存在 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']) : ''; $userType = isset($params['user_type']) ? intval($params['user_type']) : 0; $apiInfo = ApiService::make()->getInfo($apiId); $limits = isset($apiInfo['user_limits']) ? $apiInfo['user_limits'] : []; if ($limits && !in_array($userType, $limits)) { $this->error = '6004'; return false; } $data = [ 'username' => $username, 'api_id' => $apiId, 'user_type' => $userType ? $userType : 3, 'password' => get_password($password . md5($password . 'otc')), 'trade_password' => get_password($password . md5($password . 'otc')), 'mobile' => isPhone($username) ? $username : '', 'idcard' => isset($params['idcard'])? $params['idcard'] : '', 'realname' => isset($params['realname'])? $params['realname'] : '', '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 { $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 { $this->error = 2202; return false; } if ($id = $this->model->edit($data)) { MemberSettingService::make()->getInfo($id); return true; } $this->error = 2007; return false; } /** * API用户登录 * @param $params * @return array|false */ public function apiLogin($apiId, $params) { $username = isset($params['username']) ? $params['username'] : ''; $password = isset($params['password']) ? $params['password'] : ''; $userType = isset($params['user_type']) ? intval($params['user_type']) : 0; $apiKey = isset($params['api_key']) ? $params['api_key'] : ''; if (empty($username) || empty($password) || empty($apiKey) || empty($userType)) { $this->error = 1013; return false; } // 用户验证 $info = $this->model->getOne([['username', '=', $username]]); if (!$info) { // 直接注册 if (!$this->apiRegister($apiId, $params)) { return false; } $info = $this->model->getOne([['username', '=', $username]]); } else { // 密码校验 $password = get_password($password . md5($password . 'otc')); if ($password != $info['password']) { $this->error = 2002; return false; } // 使用状态校验 if ($info['status'] != 1) { $this->error = 2009; return false; } if ($info['api_id'] != $apiId) { $this->error = 6010; return false; } // 用户类型 if (!in_array($info['user_type'], [3, 4, 5])) { $this->error = 1024; return false; } } // 设置日志标题 ActionLogModel::setTitle("接口平台会员授权登录"); ActionLogModel::record($info); // JWT生成token $token = 'TB'.strtoupper(md5($info['id'] . $username).rand(100,999)); RedisService::set("apis:auths:info:{$info['id']}", $info, rand(5, 10)); RedisService::set("apis:tokens:{$token}", ['id' => $info['id'], 'info' => $info, 'token' => $token], 48 * 3600); // 登录 $updateData = ['login_time' => time(), 'login_ip' => get_client_ip()]; $this->model->where(['id' => $info['id']])->update($updateData); // 登录数据 if ($info['idcard_check'] != 1) { $appUrl = ConfigService::make()->getConfigByCode('app_download_url'); return [ 'app_url' => $appUrl, ]; } else { return [ 'token' => $token, 'user_id' => $info['id'], ]; } } /** * 身份认证 * @param $userId * @param $params * @return false */ public function auth($userId, $params) { $data = [ '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) { $data['idcard_front_img'] = $params['idcard_front_img']; } if (isset($params['idcard_back_img']) && strpos($params['idcard_back_img'], 'http') === false) { $data['idcard_back_img'] = $params['idcard_back_img']; } if (isset($params['idcard_hand_img']) && strpos($params['idcard_hand_img'], 'http') === false) { $data['idcard_hand_img'] = $params['idcard_hand_img']; } if (isset($params['bank_front_img']) && strpos($params['bank_front_img'], 'http') === false) { $data['bank_front_img'] = $params['bank_front_img']; } if (isset($params['bank_back_img']) && strpos($params['bank_back_img'], 'http') === false) { $data['bank_back_img'] = $params['bank_back_img']; } $info = $this->getInfo($userId); $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); } /** * 修改账号 * @param $userId * @param $params * @return bool */ public function modify($userId, $params) { $username = isset($params['username']) ? $params['username'] : ''; $newUsername = isset($params['new_username']) ? $params['new_username'] : ''; $password = isset($params['password']) ? $params['password'] : ''; if (empty($username) || empty($password)) { $this->error = 1013; return false; } // 用户验证 $info = $this->model->getOne([['username', '=', $username]]); if (!$info || $info['id'] != $userId) { $this->error = 2001; return false; } // 使用状态校验 if ($info['status'] != 1) { $this->error = 2009; return false; } // 密码校验 $password = get_password($password . md5($password . 'otc')); if ($password != $info['password']) { $this->error = 2002; return false; } $checkInfo = $this->model->getOne([['username', '=', $newUsername]]); if ($checkInfo && $checkInfo['id'] != $info['id']) { $this->error = 2005; return false; } if (!$this->model->where(['id' => $info['id']])->update(['username' => $newUsername, 'update_time' => time()])) { $this->error = 2021; return false; } $this->error = 2020; return true; } /** * 修改更新登录密码 * @param $userId * @param $params * @return bool */ public function updatePassword($userId, $params) { $username = isset($params['username']) ? $params['username'] : ''; $password = isset($params['password']) ? $params['password'] : ''; if (empty($username) || empty($password)) { $this->error = 1013; return false; } // 用户验证 $info = $this->model->getOne([['username', '=', $username]]); if (!$info || $info['id'] != $userId) { $this->error = 2001; return false; } // 使用状态校验 if ($info['status'] != 1) { $this->error = 2009; return false; } // 更新登录密码 $password = get_password($password . md5($password . 'otc')); if (!$this->model->where(['id' => $info['id']])->update(['password' => $password, 'update_time' => time()])) { $this->error = 2025; return false; } $this->error = 2024; return true; } /** * 修改更新交易密码 * @param $userId * @param $params * @return bool */ public function updateTradePassword($userId, $params) { $username = isset($params['username']) ? $params['username'] : ''; $tradePassword = isset($params['trade_password']) ? $params['trade_password'] : ''; if (empty($username) || empty($tradePassword)) { $this->error = 1013; return false; } // 用户验证 $info = $this->model->getOne([['username', '=', $username]]); if (!$info || $info['id'] != $userId) { $this->error = 2001; return false; } // 使用状态校验 if ($info['status'] != 1) { $this->error = 2009; return false; } // 交易密码 $password = get_password($tradePassword . md5($tradePassword . 'otc')); if (!$this->model->where(['id' => $info['id']])->update(['safe_level' => 2, 'trade_password' => $password, 'update_time' => time()])) { $this->error = 2023; return false; } $this->error = 2022; return true; } /** * 获取钱包地址密钥参数 * @param $address * @param string $type 链类型:trc-trc2.0,erc * @return mixed */ public function getWallet($address, $type = 'trc') { return $this->model->where([$type . '_address' => $address])->select(['id', $type . '_address', $type . '_hexaddress', $type . '_wif'])->first(); } /** * 获取待处理用户数据 * @param int $page * @param int $pageSize * @return array|mixed */ public function getCatchMember($page = 1, $pageSize = 500) { $cacheKey = "caches:wallet:members:{$page}_{$pageSize}"; $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, [], 'page', $page); $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('user as u', 'u.user_id', '=', 'm.id') ->leftJoin('member_setting as ms', 'ms.user_id', '=', 'm.id') ->where(['m.status' => 1,'m.idcard_check'=>1, 'm.user_type' => 2, 'u.status' => 1, '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 $num 交易数量 * @param int $tradeType 交易类型:1-购买,2-出售 */ public function getTradeMemberOptions($num, $tradeType = 1, $userId = 0, $keyword = '', $paseSize = 50) { $cacheKey = "caches:tradeMenber:{$tradeType}_" . md5($num . $userId . $keyword . $paseSize); if ($datas = RedisService::get($cacheKey)) { return $datas; } $datas = $this->model->from('member as m') ->leftJoin('user as u', 'u.user_id', '=', 'm.id') ->leftJoin('member_setting as ms', 'ms.user_id', '=', 'm.id') ->where(['m.status' => 1, 'm.user_type' => 2, 'u.status' => 1, 'm.mark' => 1]) ->where('m.usdt_num', '>=', $num) ->where(function ($query) use ($userId, $keyword) { if ($userId) { $query->whereNotIn('m.id', [$userId]); } if ($keyword) { $query->where('m.username', 'like', "%{$keyword}%"); } }) ->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("m.safe_level", 'desc') ->paginate($paseSize); $datas = $datas ? $datas->toArray() : []; $datas = isset($datas['data']) ? $datas['data'] : []; if ($datas) { RedisService::set($cacheKey, $datas, rand(10, 30)); } return $datas; } /** * 生成普通参数二维码 * @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]) ->select(['id', 'trc_usdt', 'trc_address', 'trc_wif', 'trc_hexaddress', 'erc_address', 'erc_wif', 'erc_hexaddress']) ->orderBy('trc_usdt') ->paginate($pageSize > 0 ? $pageSize : 9999999, [], 'page', $page); $datas = $datas ? $datas->toArray() : []; $datas = isset($datas['data']) ? $datas['data'] : []; if ($datas) { RedisService::set($cacheKey, $datas, rand(10, 30)); } return $datas; } }