// +---------------------------------------------------------------------- namespace App\Services\Api; use App\Models\AccountStatisticsModel; use App\Models\ActionLogModel; use App\Models\MemberBankModel; use App\Models\MemberModel; use App\Services\BaseService; use App\Services\ConfigService; use App\Services\JwtService; use App\Services\MpService; use App\Services\RedisService; use Illuminate\Support\Facades\DB; use phpQrcode\QRcode; /** * 会员管理-服务类 * @author laravel开发员 * @since 2020/11/11 * Class MemberService * @package App\Services\Api */ class MemberService extends BaseService { // 静态对象 protected static $instance = null; /** * 构造函数 * @author laravel开发员 * @since 2020/11/11 * MemberService constructor. */ public function __construct() { $this->model = new MemberModel(); } /** * 静态入口 * @return MemberService|static|null */ public static function make() { if (!self::$instance) { self::$instance = new static(); } return self::$instance; } /** * 授权登录 * @param $code * @param array $params * @return array|false */ public function login($code, $params = []) { // 账号登录 if (empty($code)) { $this->error = 1041; return false; } // 获取用户信息 $result = MpService::make()->getUserInfo($code); $openid = isset($result['openid']) ? $result['openid'] : ''; if (empty($openid)) { $this->error = 1042; return false; } // 验证是否注册,没有则注册 $where = ['openid' => $openid]; $data = $this->model->where($where) ->select(['id', 'openid', 'mobile', 'user_type', 'nickname', 'avatar', 'code', 'status', 'mark']) ->first(); $data = $data ? $data->toArray() : []; $userId = isset($data['id']) ? $data['id'] : 0; $avatar = isset($data['avatar']) ? $data['avatar'] : ''; $mobile = isset($data['mobile']) ? $data['mobile'] : ''; $nickName = isset($data['nickname']) ? $data['nickname'] : ''; $status = isset($data['status']) ? $data['status'] : 0; $mark = isset($data['mark']) ? $data['mark'] : 0; if ($data && $userId && $status != 1 && $mark == 1) { $this->error = 2015; return false; } $system = isset($params['system']) ? $params['system'] : []; $system = $system && !is_array($system) ? json_decode($system, true) : $system; $appSources = isset($system['app_sources']) && $system['app_sources'] ? $system['app_sources'] : 'ios'; $uuid = isset($system['uuid']) ? $system['uuid'] : ''; $version = isset($system['app_version']) ? $system['app_version'] : ''; if (empty($data)) { $userId = $this->model->max('id') + 1; // 推荐人 $rid = isset($params['rid']) ? intval($params['rid']) : 0; $parents = ''; if ($rid) { $inviteInfo = $this->model->where(['id' => $rid, 'mark' => 1]) ->select(['id', 'parent_id', 'parents', 'status']) ->first(); $parents = isset($inviteInfo['parents']) ? $inviteInfo['parents'] : ''; if ($inviteInfo) { $parents = $parents ? $parents . $rid . ',' : ",{$rid},"; } } $data = [ 'nickname' => '', 'openid' => $openid, 'mobile' => '', 'avatar' => '', 'parent_id' => $rid, 'parents' => $parents, 'code' => get_random_code(9, 'S', $userId), 'password' => get_password('a123456'), 'login_ip' => get_client_ip(), 'create_time' => time(), 'login_time' => time(), 'login_count' => DB::raw("login_count+1"), 'app_version' => $version, 'app_uuid' => $uuid, 'device' => $appSources == 'ios' ? 1 : 2, ]; if (!$userId = $this->model->insertGetId($data)) { $this->error = 2018; return false; } } // 更新登录信息 else if ($mark == 0 || !RedisService::get("caches:members:login_{$userId}")) { $updateData = [ 'login_ip' => get_client_ip(), 'create_time' => time(), 'login_time' => time(), 'app_uuid' => $uuid, 'login_count' => DB::raw("login_count+1"), 'app_version' => $version, 'device' => $appSources == 'ios' ? 1 : 2, 'mark' => 1, ]; if ($mark == 0) { $data['nickname'] = ''; $data['avatar'] = ''; $data['mobile'] = ''; $data['openid'] = $openid; $nickName = ''; $avatar = ''; $mobile = ''; } $this->model->where(['id' => $userId])->update($updateData); RedisService::set("caches:members:login_{$userId}", $updateData, rand(30, 60)); } // 如果未生成佣金账户则创建 if(!$accountId = AccountStatisticsModel::where(['user_id'=>$userId])->value('id')){ AccountStatisticsModel::insert(['user_id'=>$userId]); } // 获取登录授权token $token = JwtService::make()->encode($userId); // 结果返回 $result = [ 'access_token' => $token, 'info' => ['uid' => $userId, 'openid' => $openid, 'has_info' => $avatar && $nickName ? 1 : 0, 'mobile' => $mobile], ]; // 用户缓存信息 $this->error = 2019; $data['token'] = $token; unset($data['mobile']); RedisService::keyDel("caches:members:teamList*"); RedisService::set("auths:info:{$userId}", $data, 24 * 3600); return $result; } /** * 完善资料 * @param $params * @return array|false */ public function setProfile($params) { $id = isset($params['id'])? $params['id'] : 0; $code = isset($params['code'])? $params['code'] : ''; $avatar = isset($params['avatar'])? $params['avatar'] : ''; $nickname = isset($params['nickname'])? $params['nickname'] : ''; if($id<=0){ $this->error = '授权参数错误,请刷新重试'; return false; } if(empty($avatar) || empty($nickname)){ $this->error = '请先获取用户授权信息'; return false; } $userInfo = $this->model->where(['id'=>$id,'mark'=>1]) ->select(['id as uid', 'nickname','mobile', 'openid','avatar']) ->first(); $phone = isset($userInfo['mobile'])? $userInfo['mobile'] : ''; if(empty($userInfo)){ $this->error = '授权登录失败,请刷新重试'; return false; } if(empty($phone) && empty($code)){ $this->error = '请先刷新重试,授权获取手机号'; return false; } // 获取手机号信息 if($code){ $phoneData = MpService::make()->getPhoneNumber($code); $phoneData = isset($phoneData['phone_info']) ? $phoneData['phone_info'] : []; $phone = isset($phoneData['phoneNumber']) ? $phoneData['phoneNumber'] : ''; if (empty($phone)) { $this->error = MpService::make()->getError(); return false; } } $avatar = save_base64_image($avatar, 'avatar'); if(!$this->model->where(['id'=>$id])->update(['mobile'=>$phone,'nickname'=>$nickname,'avatar'=>$avatar,'update_time'=>time()])){ $this->error = '获取授权信息失败'; return false; } $this->error = '登录成功'; // 获取登录授权token $token = JwtService::make()->encode($id); RedisService::keyDel("caches:members:teamList*"); return [ 'access_token'=> $token, 'info'=> $userInfo ]; } /** * 重置密码 * @param $params * @return array|false */ public function forget($params) { // 账号登录 $mobile = isset($params['mobile']) ? trim($params['mobile']) : ''; $password = isset($params['password']) ? trim($params['password']) : ''; if (empty($params) || empty($mobile) || empty($password)) { $this->error = 1041; return false; } // 验证是否注册 if (!$userId = $this->model->where(['mobile' => $mobile, 'mark' => 1])->value('id')) { $this->error = 1038; return false; } if (!$this->model->where(['id' => $userId])->update(['password' => get_password($password), 'update_time' => time()])) { $this->error = 2030; return false; } // 操作日志 ActionLogModel::setRecord($userId, ['type' => 2, 'title' => '重置密码', 'content' => '重置登录密码', 'module' => 'member']); ActionLogModel::record(); $this->error = 2031; return true; } /** * 获取资料详情 * @param $where * @param array $field */ public function getInfo($where, array $field = [], $refresh = true) { if (empty($where)) { return false; } $fieldKey = $field ? '_' . md5(json_encode($field)) : ''; $cacheKey = "caches:members:info_" . (!is_array($where) ? $where . $fieldKey : md5(json_encode($where) . $fieldKey)); $info = RedisService::get($cacheKey); if ($info && !$refresh) { return $info; } $defaultField = ['id', 'user_type', 'realname', 'mobile','is_auth','idcard', 'nickname','company','position','department','parent_id', 'balance', 'code', 'openid','create_time', 'status', 'avatar']; $field = $field ? $field : $defaultField; if (is_array($where)) { $info = $this->model->with(['account','parent'])->where(['mark' => 1])->where($where)->select($field)->first(); } else { $info = $this->model->with(['account','parent'])->where(['mark' => 1])->where(['id' => (int)$where])->select($field)->first(); } $info = $info ? $info->toArray() : []; if ($info) { $info['create_time'] = $info['create_time']?datetime(strtotime($info['create_time']),'Y-m-d H:i') : ''; $info['position_text'] = $info['department'] && $info['position']? $info['department'].'/'.$info['position'] : ''; if (isset($info['mobile'])) { $info['mobile_text'] = $info['mobile'] ? format_mobile($info['mobile']) : ''; } $params = request()->all(); $type = isset($params['type'])?$params['type']:''; if($type == 'qrcode'){ $info['qrcode'] = MpService::make()->getMiniQrcode('pages/index/index',"share&rid={$info['id']}"); $info['qrcode'] = $info['qrcode']? get_image_url($info['qrcode']):''; } if($type == 'center'){ $info['uppers'] = $info['parent']?[$info['parent']]:[]; $info['upper_count'] = $info['parent']?1: 0; $query = $this->model->where(['parent_id'=>$info['id'],'mark'=>1])->select(['id','avatar','nickname','status']); $query1 = clone $query; $info['user_count'] = $query1->count('id'); $info['users'] = $query->limit(3)->get(); } RedisService::set($cacheKey, $info, rand(10, 20)); } return $info; } /** * 认证资料 * @param $userId * @return array|mixed */ public function authInfo($userId) { $cacheKey = "caches:members:authInfo:{$userId}"; $info = RedisService::get($cacheKey); if ($info) { return $info; } $info = $this->model->where(['id' => $userId, 'mark' => 1]) ->select(['id', 'realname','company','department','position','idcard','bank_name','bank_card','bank_branch','is_auth', 'status']) ->first(); $info = $info?$info->toArray() : []; if($info){ RedisService::set($cacheKey, $info, rand(300,600)); } return $info; } /** * 绑定收款账户 * @param $userId * @return array|mixed */ public function bindAccount($userId, $params) { if($params['type']==1){ $alipay = MemberBankModel::where(['type'=>1,'user_id'=>$userId,'mark'=>1]) ->select(['id','user_id','type','realname','account','account_remark','status']) ->first(); $alipayId = isset($alipay['id'])?$alipay['id'] : 0; $data = [ 'type'=> 1, 'user_id'=> $userId, 'realname'=>$params['realname'], 'account'=>$params['account'], 'account_remark'=>isset($params['account_remark']) && $params['account_remark']?$params['account_remark']:'支付宝', 'status'=>1 ]; if($alipayId){ $data['update_time']=time(); MemberBankModel::where(['id'=>$alipayId])->update($data); }else { $data['create_time']=time(); MemberBankModel::insertGetId($data); } } else if($params['type']==2){ $banks = MemberBankModel::where(['type'=>2,'user_id'=>$userId,'mark'=>1]) ->select(['id','user_id','type','realname','account','account_remark','status']) ->first(); $bankId = isset($banks['id'])?$banks['id'] : 0; $data = [ 'type'=>2, 'user_id'=> $userId, 'realname'=>$params['realname'], 'account'=>$params['account'], 'account_remark'=>$params['account_remark'], 'status'=>1 ]; if($bankId){ $data['update_time']=time(); MemberBankModel::where(['id'=>$bankId])->update($data); }else { $data['create_time']=time(); MemberBankModel::insertGetId($data); } }else{ $this->error = '账号类型错误'; return false; } RedisService::keyDel("caches:members:account:{$userId}*"); $this->error = '绑定收款账号成功'; return true; } /** * 团队人数 * @param $uid * @return array|int|mixed */ public function getTeamCount($uid) { $cacheKey = "caches:members:teamCount:{$uid}"; $data = RedisService::get($cacheKey); if ($data) { return $data; } $data = $this->model->from('member as a') ->where('a.parents', 'like', "%,{$uid},%") ->where(['a.status' => 1, 'a.mark' => 1]) ->count('id'); if($data){ RedisService::set($cacheKey, $data, rand(5,10)); } return $data; } /** * 生成普通参数二维码 * @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; } /** * 修改信息 * @param $userId * @param $params * @return bool */ public function modify($userId, $params) { $cacheLockKey = "caches:members:modify_{$userId}"; if (RedisService::get($cacheLockKey)) { $this->error = 1034; return false; } // 用户验证 RedisService::set($cacheLockKey, ['user_id' => $userId, 'params' => $params], rand(2, 3)); $info = $this->model->where(['id' => $userId, 'mark' => 1]) ->select(['id', 'nickname','avatar','company','position','department', 'status']) ->first(); if (!$info || $info['status'] != 1) { $this->error = 2016; RedisService::clear($cacheLockKey); return false; } // 修改数据 $data = ['update_time' => time()]; $nickname = isset($params['nickname']) ? $params['nickname'] : ''; if (isset($params['nickname']) && $nickname) { $data['nickname'] = $nickname; } $mobile = isset($params['mobile']) ? $params['mobile'] : ''; if (isset($params['mobile']) && $mobile) { $data['mobile'] = $mobile; } $company = isset($params['company']) ? $params['company'] : ''; if (isset($params['company']) && $company) { $data['company'] = $company; } $department = isset($params['department']) ? $params['department'] : ''; if (isset($params['department']) && $department) { $data['department'] = $department; } $position = isset($params['position']) ? $params['position'] : ''; if (isset($params['position']) && $position) { $data['position'] = $position; } // 头像 $avatar = isset($params['avatar']) ? $params['avatar'] : ''; if (isset($params['avatar']) && $avatar) { $data['avatar'] = save_base64_image($avatar, 'avatar'); } if (!$this->model->where(['id' => $userId])->update($data)) { $this->error = 1014; RedisService::clear($cacheLockKey); return false; } $oldAvatar = isset($info['avatar']) ? $info['avatar'] : ''; if ($avatar && $oldAvatar && ($avatar != $oldAvatar) && file_exists(ATTACHMENT_PATH . $oldAvatar)) { @unlink(ATTACHMENT_PATH . $oldAvatar); } $this->error = 1013; RedisService::clear($cacheLockKey); RedisService::clear("caches:members:authInfo:{$userId}"); RedisService::clear("caches:members:info_{$userId}"); return true; } /** * 认证 * @param $userId * @param $params * @return bool */ public function auth($userId, $params) { $cacheLockKey = "caches:members:auth_{$userId}"; if (RedisService::get($cacheLockKey)) { $this->error = 1034; return false; } // 用户验证 RedisService::set($cacheLockKey, ['user_id' => $userId, 'params' => $params], rand(2, 3)); $info = $this->model->where(['id' => $userId, 'mark' => 1]) ->select(['id', 'realname','idcard','is_auth', 'status']) ->first(); if (!$info || $info['status'] != 1) { $this->error = '账号或已被冻结,请联系客服'; RedisService::clear($cacheLockKey); return false; } if($info['is_auth'] == 1 && $info['idcard'] && $info['realname']){ $this->error = '抱歉,您已完成认证'; RedisService::clear($cacheLockKey); return false; } // 认证数据 $data = [ 'realname'=> isset($params['realname'])?$params['realname'] : '', 'company'=> isset($params['company'])?$params['company'] : '', 'idcard'=> isset($params['idcard'])?$params['idcard'] : '', 'is_auth'=> 1, 'update_time' => time() ]; if (!$this->model->where(['id' => $userId])->update($data)) { $this->error = '认证提交失败'; RedisService::clear($cacheLockKey); return false; } $this->error = '恭喜您,已完成认证'; RedisService::clear($cacheLockKey); RedisService::clear("caches:members:authInfo:{$userId}"); RedisService::keyDel("caches:members:teamList*"); return true; } /** * 获取团队列表 * @param $userId * @param $params * @return array */ public function getTeamList($userId,$params) { $page = isset($params['page'])?$params['page']: 1; $pageSize = isset($params['pageSize'])?$params['pageSize']: 12; $cacheKey = "caches:members:teamList_{$userId}:{$page}_".md5(json_encode($params)); $list = RedisService::get($cacheKey); if ($list) { return [ 'cache'=>true, 'pageSize'=> $pageSize, 'total'=>isset($list['total'])? $list['total'] : 0, 'list'=> isset($list['data'])? $list['data'] : [] ]; } $list = $this->model->with(['account'])->from('member as a') ->leftJoin('account_statistics as b','b.user_id','=','a.id') ->where(['a.parent_id'=>$userId,'b.state'=>1,'a.mark'=>1]) ->where(function($query) use($params){ $keyword = isset($params['keyword'])? $params['keyword'] : ''; if($keyword){ $query->where(function($query) use($keyword){ $query->where('a.realname','like',"%{$keyword}%") ->orWhere('a.nickname','like',"%{$keyword}%") ->orWhere('a.mobile','like',"%{$keyword}%"); }); } }) ->select(['a.id','a.realname','a.mobile','a.nickname','a.parent_id','a.avatar','a.is_auth','a.status']) ->orderBy('a.id','desc') ->paginate($pageSize > 0 ? $pageSize : 9999999); $list = $list? $list->toArray() :[]; $total = isset($list['total'])? $list['total'] : 0; if($total){ RedisService::set($cacheKey, $list, rand(5,10)); } return [ 'pageSize'=> $pageSize, 'total'=>$total, 'list'=> isset($list['data'])? $list['data'] : [] ]; } /** * 设置账户参数 * @param $userId * @param $params * @return array|false|mixed|string */ public function setting($userId, $params) { $apiUrl = ConfigService::make()->getConfigByCode('bonus_settle_url',''); if(empty($apiUrl)){ $this->error = '设置失败,参数错误'; return false; } $token = request()->headers->get('Authorization'); $token = str_replace("Bearer ", null, $token); $header = [ 'authorization: '.$token ]; $position = isset($params['position'])?trim($params['position']): ''; $point = isset($params['commission_point'])?floatval($params['commission_point']): 0; $result = httpRequest($apiUrl.'/team/setting',['id'=>$userId,'position'=>$position,'point'=>$point],'post','',5,$header); $err = isset($result['err']) && $result['err']?$result['err'] : -1; $msg = isset($result['msg']) && $result['msg']?$result['msg'] : '1003'; $data = isset($result['data']) && $result['data']?$result['data'] : []; if($err==0){ $this->error = '操作成功'; return $data; }else{ $this->error = $msg; return false; } } /** * 账号注销 * @param $userId * @return bool */ public function logOff($userId) { $info = $this->model->where(['id' => $userId, 'mark' => 1]) ->select(['id', 'password', 'status']) ->first(); $status = isset($info['status']) ? $info['status'] : 0; if (empty($info)) { $this->error = 2044; return false; } if ($status != 1) { $this->error = 2044; return false; } if (!$this->model->where(['id' => $userId])->update(['status' => 3, 'update_time' => time()])) { $this->error = 2049; return false; } $this->error = 2048; RedisService::clear("auths:info:" . $userId); return true; } }