| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623 |
- <?php
- /**
- * 描述.
- *
- * @author jim <jim458734573@gmail.com>
- * @date 2020-01-16 17:06:43
- */
- declare(strict_types=1);
- namespace App\Repositories;
- use App\Events\Task\BindPhoneEvent;
- use App\Events\Task\FillCodeEvent;
- use App\Events\Task\InviteFriendsEvent;
- use App\Events\Task\TimeTaskEvent;
- use App\Exception\ApiException;
- use App\Model\Mongo\VideoHistoryModel;
- use App\Model\TaskAwarkLogModel;
- use App\Model\UserModel;
- use App\Model\VipCardModel;
- use App\Model\VipOrderModel;
- use App\Repositories\Service\CommonService;
- use App\Repositories\Service\QueueService;
- use App\Repositories\Utils\M3u8CacheRepository;
- use App\Repositories\Utils\RandomUserInfoRepository;
- use Carbon\Carbon;
- use Hyperf\Database\Model\Builder;
- use Hyperf\DbConnection\Db;
- use KZ2\Repositories\Model\Repository;
- use Modules\Api\Services\AuthService;
- use Modules\Api\Services\UserRelationService;
- use Psr\SimpleCache\CacheInterface;
- class UserRepository extends Repository
- {
- /**
- * 账号凭证加密的key,单个APP写死
- * @var string
- */
- private $_acKey = 'SbIQUxX6hSOJ8pdb';
- /**
- * 账号凭证加密的iv,单个APP写死
- * @var string
- */
- private $_acIv = 'CJn2wekWF2OPUkXC';
- // 目前APP的用户协议名
- private $appUserScheme = 'user://';
- /**
- * @return Builder|mixed|string
- */
- public function model()
- {
- return UserModel::class;
- }
- /**
- * 随机产生昵称.
- * @return string
- */
- public function randGenerateNick()
- {
- return RandomUserInfoRepository::getNickname();
- }
- /**
- * 随机产生设备号
- * @return string
- */
- public function randGenerateDeviceNo()
- {
- return strtolower(random(32));
- }
- /**
- * app用户退出登录
- * @param $userId
- * @return bool
- */
- public function userLogout($userId)
- {
- if (!$userId) {
- return false;
- }
- $userInfo = $this->getUserInfoFromCache($userId);
- if (!$userInfo) {
- return false;
- }
- $cacheKey = (new AuthService)
- ->getUserDeviceCacheKey(
- $userInfo['device_no'],
- $userInfo['device_type']
- );
- $cache = make(CacheInterface::class);
- $cache->delete($cacheKey);
- $this->delUserCache($userId);
- return true;
- }
- /**
- * 从cache里面取用户信息 头像不建议在这里面拼接URL
- * @param $userId
- * @return array|null
- */
- public function getUserInfoFromCache($userId)
- {
- if (!$userId) {
- return null;
- }
- $cacheKey = 'user_info:'.$userId;
- //缓存时间 随机2-3小时内
- $cacheTime = mt_rand(7200, 10800);
- $result = make(CacheInterface::class)
- ->remember(
- $cacheKey,
- $cacheTime,
- function () use ($userId) {
- $creatorRepo = make(CreatorRepository::class);
- $creatorTotalCoin = $creatorTotalIncome = $creatorIncome = $creatorCoin = 0;
- $creatorObj = $creatorRepo->detail($userId, ['id', 'total_coin', 'total_income']);
- if (!empty($creatorObj)) {
- $creatorTotalCoin = $creatorObj->total_coin;
- $creatorTotalIncome = $creatorObj->total_income;
- }
- $tempData = array();
- $dbResult = UserModel::query()->where('code', $userId)
- ->first();
- if ($dbResult) {
- $dbResult = $dbResult->toArray();
- //去掉不必要字段
- if ($dbResult['status'] != 1) {
- return null;
- }
- // $dbResult['avatar'] = make(CommonService::class)
- // ->getImageUrl($dbResult['avatar']);
- $dbResult['birth'] = strval($dbResult['birth']);
- $dbResult['vip_expired'] = strval($dbResult['vip_expired']);
- $dbResult['is_vip'] = 'n';
- $now = Carbon::now();
- $vipExpired = Carbon::parse($dbResult['vip_expired']);
- if ($dbResult['vip_expired'] && $vipExpired > $now) {
- $dbResult['is_vip'] = 'y';
- }
- $relation = make(UserRelationService::class);
- $dbResult['fans'] = $relation->getTotal('fans', $userId);
- $dbResult['flow'] = $relation->getTotal('flow', $userId);
- $dbResult['like'] = $relation->getLike($userId);
- unset($now);
- unset($vipExpired);
- $tempData = $dbResult;
- $tempData['creator_total_coin'] = $creatorTotalCoin;
- $tempData['creator_total_income'] = $creatorTotalIncome;
- }
- return $tempData;
- }
- );
- return $result;
- }
- /**
- * 清除用户的cache信息 操作了用户 如 封禁啊、增加会员了啊什么的调用此方法
- * @return bool
- */
- public function delUserCache($userId)
- {
- $cacheKey = 'user_info:'.$userId;
- make(CacheInterface::class)->delete($cacheKey);
- return true;
- }
- /**
- * 个人中心数据
- * @param $userId
- * @return array
- */
- public function getUserInfoData($userId)
- {
- $userInfo = $this->getUserInfoFromCache($userId);
- if (!$userInfo) {
- throw new ApiException('帳號異常');
- }
- $user_count = make(VideoHistoryModel::class)->db()->countDocuments(
- ['uid' => $userInfo['id'], 'date' => Carbon::now()->toDateString()]
- );
- $taskLogRepo = make(TaskAwarkLogRepository::class);
- $result = array(
- 'id' => $userInfo['id'],
- 'code' => $userInfo['code'],
- 'nick' => $userInfo['nick'].'',
- 'coins' => $userInfo['coins'],
- 'avatar'=> M3u8CacheRepository::getImageUrl($userInfo['avatar']),
- 'intro' => $userInfo['intro'].'',
- 'gender'=> intval($userInfo['gender']),
- 'is_vip'=> $userInfo['is_vip'],
- 'user_vip_level' => 0, // 字段vip_level,设计目的是给裂变业绩使用,所以此处有2层含义,需要通过is_vip来判断.
- 'play_num_notice'=> '',
- 'bind_mobile' => $userInfo['mobile'] ? '+'. $userInfo['area_code'] . $userInfo['mobile'] : '', // 是否注册绑定手机号通过这个是否为空字符串判断.
- 'flow' => $userInfo['flow'],
- 'fans' => $userInfo['fans'],
- 'like' => $userInfo['like'],
- 'invite' => $userInfo['invite'],
- 'has_parent'=> $userInfo['parent_uid'] > 0 ? 'y' : 'n',
- 'parent_uid' => $userInfo['parent_uid'],
- 'balance' => !empty($userInfo['balance']) ? $userInfo['balance'] : 0, // 余额
- 'max_view' => intval($userInfo['max_view']),
- 'channel_code' => $userInfo['channel_id'], // 渠道号.
- 'creator_level' => $userInfo['creator_level'] ?? 0, // 创作者等级.
- );
- $playNumNotice = '';
- $userVipLevel = 0;
- $commentSurplus = 0; // 剩余评论数
- $videoSurplus = 0; // 剩余观影次数.
- $vipDaysSurplus = 0; // VIP剩余天数.
- $vipTitle = ''; // VIP套餐名称.
- $todayTaskVideoNum = make(TaskAwarkLogRepository::class)->coutTodayOnce($userInfo['code'], TaskAwarkLogModel::REWARD_TYPE_MOVIE_CONUT);
- $videoSurplus = intval($userInfo['max_view']) - $user_count + $todayTaskVideoNum;
- if ($videoSurplus < 0) {
- // 容错
- $videoSurplus = 0;
- }
- if ($userInfo['is_vip'] == 'y') {
- $userVipLevel = $userInfo['vip_level'];
- $vipDaysSurplus = abs(Carbon::now()->diffInDays($userInfo['vip_expired']));
- $videoSurplus = 999999;
- if ($vipDaysSurplus > (10 * 365)) {
- $playNumNotice = '无限观看';
- } else {
- $playNumNotice = '剩余:' . strval($vipDaysSurplus) . '天';
- }
- } else {
- $playNumNotice = '剩余:' . strval($vipDaysSurplus) . '天';
- }
- $result['play_num_notice'] = $playNumNotice;
- $result['user_vip_level'] = $userVipLevel;
- // 最近购买最好的VIP.
- if ($vipDaysSurplus > 0) {
- $columns = ['id', 'vip_id', 'user_code', 'vip_title'];
- $lastVipObj = VipOrderModel::query()->where(['user_id' => $userInfo['id'], 'status' => 1])->orderBy('id', 'DESC')->first($columns);
- if (!empty($lastVipObj)) {
- $vipTitle = $lastVipObj->vip_title;
- }
- }
- $result['vip_title'] = $vipTitle; // VIP套餐名称.
- // 当天评论次数
- $toDayCommentSurplus = $taskLogRepo->coutTodayOnce($userId, TaskAwarkLogModel::REWARD_TYPE_COMMENT_COUNT);
- //找回账号的凭证
- $account = $this->appUserScheme .$result['code'];
- $account = hand_encrypt($account, $this->_acKey, $this->_acIv);
- $result['account_qrcode_content'] = $account;
- // TODO 给前端同学补结构,后面写业务逻辑.
- $result['video_surplus'] = $videoSurplus; // 剩余观影次数.
- $result['hotel_surplus'] = $userInfo['max_open_house']; // 开房查询剩余次数. todo 已开房次数还没减
- $result['vip_days_surplus'] = $vipDaysSurplus; // VIP剩余天数.
- $result['max_comment'] = $commentSurplus + $userInfo['max_comment'] + $toDayCommentSurplus; // 每日最大评论数.
- $result['comment_used'] = make(CommentRepository::class)->countToday($userInfo['code']); // 今日使用过评论数.
- $commentSurplus = $result['max_comment'] - $result['comment_used'];
- if ($commentSurplus < 0) {
- // 容错.
- $commentSurplus = 0;
- }
- $result['comment_surplus'] = $commentSurplus; // 今日剩余评论数.
- return $result;
- }
- /**
- * 创建用户qr内容。
- * @param $uid
- * @return string
- */
- public function createUserQrCode($uid)
- {
- $info = $this->appUserScheme.$uid;
- return hand_encrypt($info, $this->_acKey, $this->_acIv);
- }
- /**
- * 根据账号凭证找回账号
- * @param string $userId 当前账号邀请码
- * @param string $qrCode 要找回的账号的二维码内容
- * @return bool
- */
- public function findByQrCode($userId, $qrCode)
- {
- //当前账号
- $newUserInfo = $this->getUserInfoFromCache($userId);
- if (!$newUserInfo) {
- throw new ApiException('[1]帳號異常');
- }
- $account = hand_decrypt($qrCode, $this->_acKey, $this->_acIv);
- if (empty($account)) {
- throw new ApiException('[1]无效二维码内容');
- }
- $patternTxt = str_replace('/', '\\/', $this->appUserScheme);
- if (!preg_match('/^('. $patternTxt .')/i', $account)) {
- throw new ApiException('[2]无效二维码内容');
- }
- $account = str_replace($this->appUserScheme, '', $account);
- $oldUserInfo = $this->getUserInfoFromCache($account);
- if (!$oldUserInfo) {
- throw new ApiException('[2]帳號異常');
- }
- if ($newUserInfo['id'] == $oldUserInfo['id']) {
- throw new ApiException('此身份卡为当前账号,请勿重复扫描');
- }
- Db::beginTransaction();
- try {
- //交换两个账号的device_no
- //把旧账号的设备号、设备类型给新账号
- $result1 = UserModel::query()
- ->where('id', $newUserInfo['id'])
- ->update(
- array(
- 'device_no'=>$oldUserInfo['device_no'],
- 'device_type'=>$oldUserInfo['device_type'],
- 'finger_hash'=>$oldUserInfo['finger_hash'],
- )
- );
- //把新账号的设备号、设备类型给旧账号
- $result2 = UserModel::query()->where('id', $oldUserInfo['id'])
- ->update(
- array(
- 'device_no'=>$newUserInfo['device_no'],
- 'device_type'=>$newUserInfo['device_type'],
- 'finger_hash'=>$newUserInfo['finger_hash'],
- )
- );
- if ($result1 && $result2) {
- Db::commit();
- //退出登录
- $this->userLogout($newUserInfo['code']);
- $this->userLogout($oldUserInfo['code']);
- return true;
- }
- } catch (\Exception $e) {
- var_dump($e->getMessage());
- }
- Db::rollBack();
- return false;
- }
- /**
- * 绑定手机号、手机号不存在则绑定手机号。手机号存在则为根据手机号找回账号
- * @param string $userId
- * @param string $phone
- * @param string $code
- * @return bool
- */
- public function bindPhone($userId, $phone, $type)
- {
- if (!$userId || !$phone) {
- throw new ApiException('參數錯誤');
- }
- $userInfo = $this->getUserInfoFromCache($userId);
- if (!$userInfo) {
- throw new ApiException('帳號異常');
- }
- //处理逻辑
- $mobileUser = make(UserModel::class)
- ->where('area_code', '=', 86)
- ->where('mobile', '=', $phone)
- ->first();
- if ($type == 2 && $mobileUser) {
- throw new ApiException('该手机号已经绑定');
- }
- if ($type == 1) {
- if (empty($mobileUser)) {
- throw new ApiException('账号不存在,请确认你的手机号是否正确');
- }
- //手机号存在,实际逻辑为找回账号、交换两个用户的设备号信息
- $mobileUser = $mobileUser->toArray();
- Db::beginTransaction();
- try {
- //交换两个账号的device_no
- //把手机号账号的设备号、设备类型给当前账号
- $result1 = UserModel::query()->where('id', $userInfo['id'])
- ->update(
- array(
- 'device_no'=>$mobileUser['device_no'],
- 'device_type'=>$mobileUser['device_type'],
- 'finger_hash'=>$mobileUser['finger_hash'],
- )
- );
- //把当前账号的设备号、设备类型给手机号账号
- $result2 = UserModel::where('id', $mobileUser['id'])
- ->update(
- array(
- 'device_no'=>$userInfo['device_no'],
- 'device_type'=>$userInfo['device_type'],
- 'finger_hash'=>$userInfo['finger_hash'],
- )
- );
- if ($result1 && $result2) {
- Db::commit();
- //退出登录
- $this->userLogout($userInfo['code']);
- $this->userLogout($mobileUser['code']);
- return true;
- }
- } catch (\Exception $e) {
- }
- Db::rollBack();
- return false;
- } else {
- //手机号不存在、直接绑定手机号
- UserModel::query()->where('id', $userInfo['id'])->update(
- array(
- 'mobile'=>$phone,
- )
- );
- //绑定手机号
- dispatch_event(new BindPhoneEvent(['user_id' => $userInfo['code']]));
- $this->userLogout($userInfo['code']);
- return true;
- }
- }
- /**
- * 更新用户基本信息
- * @param $userId
- * @param $data
- */
- public function updateUserData($userId, $data)
- {
- if (!$userId || !$data) {
- throw new ApiException('參數錯誤');
- }
- $userInfo = $this->getUserInfoFromCache($userId);
- if (!$userInfo) {
- throw new ApiException('帳號異常');
- }
- $commonService = make(CommonService::class);
- $updateData = array();
- if (isset($data['nick'])) {
- $data['nick'] = $commonService->filterString($data['nick']);
- $tempLen = mb_strlen($data['nick'], 'utf-8');
- if ($tempLen > 9) {
- throw new ApiException('暱稱最長10個字符');
- }
- $updateData['nick'] = $data['nick'];
- }
- if (isset($data['avatar'])) {
- $tempLen = strpos($data['avatar'], 'ceb');
- if (!$tempLen) {
- throw new ApiException('頭像地址錯誤');
- }
- $updateData['avatar'] = $data['avatar'];
- }
- if (isset($data['intro'])) {
- $data['intro'] = $commonService->filterString($data['intro']);
- $tempLen = mb_strlen($data['intro'], 'utf-8');
- if ($tempLen > 199) {
- throw new ApiException('簡介最長200個字符');
- }
- $updateData['intro'] = $data['intro'];
- }
- if (isset($data['gender'])) {
- $genderArr = array(0,1,2,3);
- if (!in_array($data['gender'], $genderArr)) {
- throw new ApiException('性別錯誤');
- }
- $updateData['gender'] = $data['gender'];
- }
- if (isset($data['birth'])) {
- $updateData['birth'] = $data['birth'];
- }
- if (isset($data['live_code'])) {
- $updateData['live_code'] = $data['live_code'];
- }
- if (empty($updateData)) {
- throw new ApiException('無更新');
- }
- UserModel::query()->where('id', $userInfo['id'])->update($updateData);
- $this->delUserCache($userId);
- return true;
- }
- /**
- * 绑定邀请码
- * @param string $userId
- * @param string $parentCode
- */
- public function bindCode($userId, $parentCode)
- {
- if (!$userId || !$parentCode || $userId == $parentCode) {
- throw new ApiException('參數錯誤');
- }
- $userInfo = $this->getUserInfoFromCache($userId);
- $parentUser = $this->getUserInfoFromCache($parentCode);
- if (!$userInfo) {
- throw new ApiException('帳號異常');
- }
- if (!$parentUser) {
- throw new ApiException('邀請碼不存在');
- }
- //已绑定
- if ($userInfo['parent_uid']) {
- throw new ApiException('已綁定');
- }
- //互相推荐的情况
- if ($parentUser['parent_uid'] == $userInfo['code']) {
- throw new ApiException('綁定異常');
- }
- UserModel::query()->where('id', $userInfo['id'])
- ->update(
- array(
- 'parent_uid'=>$parentUser['code'],
- )
- );
- //会员裂变关系逻辑 丢队列异步执行
- make(QueueService::class)->createUserRelationJob(['invite_id' => $parentUser['code'], 'invited_id' => $userInfo['code']]);
- // 绑定邀请码任务
- dispatch_event(new FillCodeEvent(['user_id' => $userInfo['code']]));
- // 邀请好友任务
- dispatch_event(new InviteFriendsEvent(['user_id' => $parentUser['code']]));
- // 限时任务队列
- make(QueueService::class)->timeTaskSendRewardJob(['user_id' => $parentUser['code']], 5);
- $this->delUserCache($userId);
- $this->delUserCache($parentCode);
- return true;
- }
- /**
- * 解绑手机号
- * @param string $userId
- * @param string $phone
- * @param string $code
- * @return bool
- */
- public function unbindPhone($userId, $phone)
- {
- if (!$userId || !$phone) {
- throw new ApiException('參數錯誤');
- }
- $userInfo = $this->getUserInfoFromCache($userId);
- if (!$userInfo) {
- throw new ApiException('帳號異常');
- }
- //处理逻辑
- $mobileUser = make(UserModel::class)
- ->where('area_code', '=', 86)
- ->where('mobile', '=', $phone)
- ->first();
- if ($mobileUser) {
- if ($mobileUser->mobile != $phone) {
- throw new ApiException('帳號異常');
- }
- $mobileUser->mobile = '';
- //手机号存在,实际逻辑为找回账号、交换两个用户的设备号信息
- $mobileUser = $mobileUser->toArray();
- Db::beginTransaction();
- try {
- $mobileUser->save();
- Db::commit();
- } catch (\Exception $e) {
- }
- Db::rollBack();
- return false;
- } else {
- throw new ApiException('帳號異常');
- }
- }
- /**
- * 获取aes-key
- * @return string
- */
- public function getAcKey()
- {
- return $this->_acKey;
- }
- /**
- * 获取aes-iv
- * @return string
- */
- public function getAcIv()
- {
- return $this->_acIv;
- }
- /**
- * 获取系统头像
- * @return mixed
- */
- public function getSysAvatars()
- {
- $cacheRepo = make(CacheInterface::class);
- $cacheKey = 'user:sys_avatars';
- $arrData = $cacheRepo->rememberForever($cacheKey, function () {
- $arrData = [];
- $filePrefix = 'f2|/'. env('STATIC_DIR_NAME', 'doukui') . '/avatars/a_';
- $maxNum = 11;
- for ($i = 1; $i <= $maxNum; $i++) {
- $tmpNum = str_pad(strval($i), 3, '0', STR_PAD_LEFT);
- $groupUrl = $filePrefix . $tmpNum . '.ceb';
- $arrData[] = $groupUrl;
- }
- return $arrData;
- });
- return $arrData;
- }
- }
|