// +---------------------------------------------------------------------- declare (strict_types=1); namespace app\api\model; use app\api\validate\user\Info as ValidateInfo; use app\common\model\UnlockOrder; use app\common\model\UnlockUser; use think\facade\Cache; use app\api\service\User as UserService; use app\api\model\UserOauth as UserOauthModel; use app\common\model\User as UserModel; use cores\exception\BaseException; use yiovo\captcha\facade\CaptchaApi; /** * 用户模型类 * Class User * @package app\api\model */ class User extends UserModel { /** * 隐藏字段 * @var array */ protected $hidden = [ 'open_id', 'is_delete', 'store_id', 'create_time', 'update_time' ]; /** * 获取列表 * @param array $param 查询条件 * @param int $listRows 分页数量 * @return mixed|\think\model\Collection|\think\Paginator * @throws \think\db\exception\DbException */ public function getList(array $param = [], int $listRows = 15) { // 整理查询参数 $params = array_merge($param, ['status' => 1,'is_delete'=>0]); // 获取列表 $list = parent::getList($params, $listRows); if ($list->isEmpty()) { return $list; } // 整理列表数据并返回 return $this->setListDataFromApi($list); } /** * 获取生源学校用户列表 * @param array $param 查询条件 * @param int $listRows 分页数量 * @return mixed|\think\model\Collection|\think\Paginator * @throws \think\db\exception\DbException */ public function getSourceSchoolUserList(array $param = [], int $listRows = 15) { // 整理查询参数 $params = array_merge($param, ['status' => 1, 'is_delete' => 0, 'ui.status' => 1, 'user_type' => 1]); // 获取商品列表 $list = parent::getList($params, $listRows); if ($list->isEmpty()) { return $list; } // 整理列表数据并返回 return $this->setListDataFromApi($list, $params); } /** * 设置展示的数据 api模块 * @param $info * @return mixed */ private function setListDataFromApi($list, $params = []) { // 是否验证和统计解锁用户 $checkType = isset($params['check_type'])? $params['check_type'] : 0; $userId = isset($params['user_id'])? $params['user_id'] : 0; $schoolId = isset($params['school_id'])? $params['school_id'] : 0; $list = $this->setListData($list, function ($data) use($checkType, $userId, $schoolId){ $data['avatar'] = isset($data['avatar'])? $data['avatar'] : []; unset($data['avatar']); $data['is_locked'] = 2; // 是否验证已被解锁 if($checkType == 1){ $data['is_locked'] = (int)UnlockUser::checkUserByUser($data['user_id'], $userId, $schoolId); } // 整理数据 api模块 $this->setDataFromApi($data); // 隐藏冗余的字段 $hidden = ['user_type','user_login','home_bg','update_time','grade_id','platform','status','country','province','city','address','address_id','balance','points','last_login_time','pay_money','expend_money','last_login_time']; $this->hidden(array_merge($this->hidden, $hidden)); }); $list = $list? $list->toArray() : []; if($checkType == 1 && $userId>0 && isset($list['total'])){ $list['locked_num'] = (int)UnlockUser::getCountByUser($userId, $schoolId); $list['lock_num'] = max(0,$list['total']-$list['locked_num']); } asort($list); return $list; } /** * 整理数据 api模块 * @param $info * @return mixed */ private function setDataFromApi($info) { return $this->setData($info, function ($data) { $data['region_name'] = $data['region_id']? Region::getNameById($data['region_id']):''; // 粉丝数 $data['fans_num'] = $data['user_id']? UserFans::getFansNum($data['user_id']): 0; }); } /** * 获取器:隐藏手机号中间四位 * @param string $value * @return string */ public function getMobileAttr(string $value): string { return strlen($value) === 11 ? hide_mobile($value) : $value; } /** * 获取用户信息 * @param string $token * @return User|array|false|null * @throws BaseException */ public static function getUserByToken(string $token) { // 检查登录态是否存在 if (!Cache::has($token)) { return false; } // 用户的ID $userId = (int)Cache::get($token)['user']['user_id']; // 用户基本信息 $userInfo = self::detail($userId); $userInfo['info']=$userInfo['info']? $userInfo['info'] : []; if($userInfo['info']){ $userInfo['info']['school']= isset($userInfo['info']['school']) && $userInfo['info']['school']? $userInfo['info']['school'] : []; } if (empty($userInfo) || $userInfo['is_delete']) { throwError('很抱歉,用户信息不存在或已删除', config('status.not_logged')); } // 获取用户关联的第三方用户信息(当前客户端) try { if(getPlatform() && getPlatform() != 'MP-WEIXIN'){ $userInfo['currentOauth'] = UserOauthModel::getOauth($userId, getPlatform()); } } catch (\Throwable $e) { throwError($e->getMessage()); } return $userInfo; } /** * 绑定手机号(当前登录用户) * @param array $data * @return bool * @throws BaseException */ public function bindMobile(array $data): bool { // 当前登录的用户信息 $userInfo = UserService::getCurrentLoginUser(true); // 验证绑定的手机号 $this->checkBindMobile($data); // 更新手机号记录 return $userInfo->save(['mobile' => $data['mobile']]); } /** * 验证绑定的手机号 * @param array $data * @return void * @throws BaseException */ private function checkBindMobile(array $data): void { // 验证短信验证码是否匹配 if (!CaptchaApi::checkSms($data['smsCode'], $data['mobile'])) { throwError('短信验证码不正确'); } // 判断手机号是否已存在 if (static::checkExistByMobile($data['mobile'])) { throwError('很抱歉,该手机号已绑定其他账户'); } } /** * @param array $data * @return string * @throws BaseException */ public function saveInfo(array $data): string { // 修改手机号需要验证验证码 $userInfo = UserService::getCurrentLoginUser(true); // 验证信息 $this->checkInfo($data, $userInfo); $info = UserInfo::detail($userInfo['user_id']); if(!is_null($info) && $info['school_id'] && $info['school_id'] != $data['school_id']){ throwError('已认证注册,无法修改学校,请联系客服'); } if ((!is_null($info) && $info['school_id']) && $userInfo['user_type'] && $data['user_type'] != $userInfo['user_type']){ throwError('账号类型不可修改'); } $userInfo->transaction(function () use ($data, $userInfo, $info) { try { $userData = [ 'user_id'=> $userInfo['user_id'], 'real_name'=> $data['real_name'], 'gender'=> (int)$data['gender'], 'age'=> isset($data['age'])? intval($data['age']) : 0, 'student_no'=>isset($data['student_no'])? $data['student_no'] :'', 'user_login'=> isset($data['user_login'])? $data['user_login'] :'', 'mobile'=> $data['mobile'], ]; if($userInfo['user_type']<=0 || (is_null($info) || $info['school_id']<=0)){ $userData['user_type'] = (int)$data['user_type']; } $userInfo->save($userData); $infoData = [ 'user_id'=> $userInfo['user_id'], 'school_id'=> (int)$data['school_id'], 'position'=> isset($data['position'])? intval($data['position']) : 0, 'speciality'=> isset($data['speciality'])? intval($data['speciality']) : 0, 'qq'=> isset($data['qq'])? $data['qq'] : '', 'idcard'=> isset($data['idcard'])? $data['idcard'] :'', 'idcard_front_img'=> isset($data['idcard_front_img'])? $data['idcard_front_img'] :'', 'work_certify'=> isset($data['work_certify'])? $data['work_certify'] :'', 'education_certify'=> isset($data['education_certify'])? $data['education_certify'] :'', 'parent_name'=> isset($data['parent_name'])? $data['parent_name'] :'', 'admission_year'=> isset($data['admission_year'])? $data['admission_year'] : '', 'status'=> $data['user_type'] != 3? 1 : (isset($info['status'])? $info['status'] : 2), ]; // 资料是否被修改过 if($this->checkModifyInfo($data, $info)){ $infoData['status'] = 2; } if(is_null($info)){ (new UserInfo)->save($infoData); }else{ $info->save($infoData); } // 更新生源学校生源数量 $model = new SourceShool(); $model->setInc(['source_shools_id'=> (int)$data['school_id']],'students_num', 1); } catch(\Exception $exception){ throwError('保存失败'); } }); return $info || $data['user_type']!=3? '保存成功' : '保存成功,等待审核'; } /** * 验证重要资料是否已修改 * @param array $data * @param $info * @return bool */ public function checkModifyInfo(array $data, $info): bool { if($data['user_type'] != 3){ return false; } if(is_null($info)){ return true; } $checkFields = ['idcard','mobile','real_name','user_login','student_no']; foreach($checkFields as $field){ if(isset($data[$field]) && $info[$field] != $data[$field]){ return true; } } return false; } /** * 验证用户信息 * @param array $data * @param array $userInfo * @return bool * @throws BaseException */ private function checkInfo(array $data, UserModel $userInfo): void { $validate = new ValidateInfo; if (!$validate->check($data)) { throwError($validate->getError()); } if($data['user_type'] == 2 && empty($data['parent_name'])){ throwError('家长姓名不为空'); } if(empty($data['school_id'])){ throwError('学校不为空'); } if($data['user_type'] == 1){ /*if(empty($data['admission_year'])){ throwError('请选择入学年份'); } if(empty($data['education_certify'])){ throwError('请上传教育证明'); }*/ }else if($data['user_type'] == 3){ if(empty($data['position'])){ throwError('请选择职务'); } /*if(empty($data['work_certify'])){ throwError('请上传职务证明'); }*/ } if($userInfo['mobile'] != $data['mobile']) { if (empty($data['smsCode'])) { throwError('短信验证码不为空'); } // 验证短信验证码是否匹配 if ($data['smsCode'] && ($data['smsCode']!= '123456' && !CaptchaApi::checkSms($data['smsCode'], $data['mobile']))) { throwError('短信验证码不正确'); } } $checkId = UserInfo::checkExistByIdcard($data['idcard']); if($data['idcard'] && $checkId && $userInfo['user_id'] != $checkId){ throwError('身份证号码已被使用'); } /*if(empty($data['idcard_front_img'])){ throwError('请上传身份证明'); }*/ $chekId = self::checkExistByMobile($data['mobile']); if($data['mobile'] && $chekId && $userInfo['user_id'] != $chekId){ throwError('手机号码已被使用'); } } /** * 获取生源学校下的所有生源用户ID * @param $sourceSchoolId * @return mixed */ public static function getSourceUserIds($sourceSchoolId, $ids=[]) { return self::alias('u') ->leftJoin('user_info ui','ui.user_id=u.user_id') ->where(['ui.school_id'=> $sourceSchoolId,'u.user_type'=> 1, 'u.is_delete'=> 0,'u.status'=>1,'ui.status'=>1]) ->whereNotIn('u.user_id', $ids) ->column('u.user_id'); } }