// +---------------------------------------------------------------------- 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 $value * @return string */ public function getHomeBgAttr(string $value): string { return $value? getPreview($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')); } if ($userInfo['status'] != 1) { 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 bool * @throws BaseException */ public function setImage(array $data): bool { // 当前登录的用户信息 $userInfo = UserService::getCurrentLoginUser(true); //var_dump($userInfo); $type = isset($data['type'])? intval($data['type']) : 0; if($type == 1){ $avatarId = isset($data['file_id'])? intval($data['file_id']) : 0; if($avatarId<=0){ throwError('请先上传头像'); } return $userInfo->save(['avatar_id'=> $avatarId]); }else if($type == 2){ $filePath = isset($data['file_path'])? $data['file_path'] : ''; if(empty($filePath)){ throwError('请先上传背景图片'); } return $userInfo->save(['home_bg'=> $filePath]); } return false; } /** * 验证绑定的手机号 * @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'); } }