pex_fix.$this->encrypt($str); }else{ return $this->encrypt($str); } } /** * 用户注册 * @param $code * @return \app\main\model\object\ReturnObject */ public function userRegister($code) { $str = $this->decrypt($code); if ($str === false) { return $this->setCode(ClientApiConstants::REGISTER_FAIL)->setMsg('微信动态码错误!')->getReturn(); } $nowStr = date(self::REGISTER_RULE); $codeTimeStr = substr($str, 0, strlen($nowStr)); if ($nowStr != $codeTimeStr) { return $this->setCode(ClientApiConstants::REGISTER_TIMEOUT)->setMsg('微信动态码超时!')->getReturn(); } $str = str_replace($nowStr, '', $str);//去掉时间串后的字符串 $separateIdx = strpos($str, '_'); if ($separateIdx === false) { return $this->setCode(ClientApiConstants::REGISTER_TIMEOUT)->setMsg('微信动态码超时!')->getReturn(); } $channelId = substr($str, 0, $separateIdx); $openId = substr($str, $separateIdx + 1, strlen($str) - $separateIdx - 1); $userId = OfficialAccountsService::instance()->getOpenidModel()->getUserId($channelId, $openId); if (empty($userId)) { return $this->setCode(ClientApiConstants::REGISTER_NON_EXISTENT_USER)->setMsg('用户不存在!')->getReturn(); } //维护绑定时间 $userInfo = $this->getUserModel()->getUserInfo($userId); if(empty($userInfo->bindtime)){ UserService::instance()->update(['bindtime' => time()], ['id' => $userId]); } # S: APP用户绑定手机号打点 $dotData = new DotObject(); $userobj = $userInfo; $dotData->user_id = $userobj['id']; $dotData->channel_id = $userobj['channel_id']; $dotData->sex = $userobj['sex']; $dotData->business_line = PayConstants::BUSINESS_APP; $dotData->action_type = MqConstants:: ROUTING_KEY_APP_BIND_CODE; $dotData->type = MqConstants::MSG_TYPE_APP_BIND_CODE; $dotData->event_time = Request::instance()->server('REQUEST_TIME'); LogService::info('[ codeRegister ] APP用户绑定手机号打点'); MqService::instance()->sendMessage($dotData); # End: APP用户绑定手机号打点 return $this->setData($userInfo)->getReturn(); } /** * 获取Loading页面配置信息 * @param $userInfo * @param $clientVersion * @return \app\main\model\object\ReturnObject * @throws \Exception */ public function getClientConfigLoading($userInfo, $clientVersion) { $clientConfigList = $this->fetchClientConfig($userInfo, $clientVersion, ClientApiConstants::CLIENT_CONFIG_FUN_TYPE_LOADING, 1); if (count($clientConfigList) > 0) { $data = current($clientConfigList); $info = $this->ClientConfigFormat($data); return $this->setData($info)->getReturn(); } else { return $this->setCode(ErrorCodeConstants::RESULT_EMPTY)->getReturn(); } } /** * 获取书架配置信息 * @param $userInfo * @param $clientVersion * @return \app\main\model\object\ReturnObject * @throws \Exception */ public function getClientConfigBookShelf($userInfo, $clientVersion) { $clientConfigList = $this->fetchClientConfig($userInfo, $clientVersion, ClientApiConstants::CLIENT_CONFIG_FUN_TYPE_BOOKSHELF, 5); $result = []; foreach ($clientConfigList as $item) { $tmp = $this->ClientConfigFormat($item); $result[] = $tmp; } if (count($result) > 0) { return $this->setData($result)->getReturn(); } else { return $this->setCode(ErrorCodeConstants::RESULT_EMPTY)->getReturn(); } } /** * 获取弹窗配置信息 * @param $userInfo * @param $clientVersion * @param $position * @return \app\main\model\object\ReturnObject * @throws \Exception */ public function getClientConfigAlert($userInfo, $clientVersion, $position) { $clientConfigList = $this->fetchClientConfig($userInfo, $clientVersion, ClientApiConstants::CLIENT_CONFIG_FUN_TYPE_ALERT, 1, $position); if (count($clientConfigList) > 0) { $data = current($clientConfigList); return $this->setData($data)->getReturn(); } else { return $this->setCode(ErrorCodeConstants::RESULT_EMPTY)->getReturn(); } } private function ClientConfigFormat($clientConfigInfo) { $result = [ 'image_url' => $clientConfigInfo['pic_url'], 'delay_time' => $clientConfigInfo['count_down'], 'start_time' => strtotime($clientConfigInfo['start_time']), 'end_time' => strtotime($clientConfigInfo['end_time']), ]; if ($clientConfigInfo['type'] == ClientApiConstants::CLIENT_CONFIG_TYPE_BOOK_INFO) { $result['uri'] = $this->parseAppUrl('bookinfo', ['book_id' => $clientConfigInfo['book_id']]); } elseif ($clientConfigInfo['type'] == ClientApiConstants::CLIENT_CONFIG_TYPE_BOOK_CHAPTER) { $result['uri'] = $this->parseAppUrl('chapter', ['book_id' => $clientConfigInfo['book_id']]); } elseif ($clientConfigInfo['type'] == ClientApiConstants::CLIENT_CONFIG_TYPE_URL) { $result['uri'] = $clientConfigInfo['url']; } elseif ($clientConfigInfo['type'] == ClientApiConstants::CLIENT_CONFIG_TYPE_BOOK_ACTIVITY) { $webHost = Config::get("site.client_web_host"); $result['uri'] = sprintf('%s/clientweb/activity/index?id=%s', $webHost, $clientConfigInfo['client_activity_id']); } return $result; } private function fetchClientConfig($userInfo, $clientVersion, $funType, $limit, $position = null) { $key = "APCC:$clientVersion:$funType"; $userPayTypeCond = [ClientApiConstants::USER_PAY_ALL]; if (!empty($userInfo)) { $userIsPay = $userInfo['is_pay']; $key .= ":$userIsPay"; if ($userIsPay == 1) { $userPayTypeCond[] = ClientApiConstants::USER_PAY_PAYED; } else { $userPayTypeCond[] = ClientApiConstants::USER_PAY_UNPAY; } } else { $key .= ":0"; } if (!empty($position)) { $key .= ":$position"; } $redis = Redis::instance(); if ($redis->exists($key)) { $res = json_decode($redis->get($key), true); } else { $model = $this->getClientConfigModel() ->where('fun_type', $funType) ->where('status', ClientApiConstants::CLIENT_CONFIG_NORMAL) ->where('start_time', '<', date('Y-m-d H:i:s')) ->where('end_time', '>', date('Y-m-d H:i:s')) ->whereIn('user_pay_type', $userPayTypeCond) ->whereIn('version', [$clientVersion, '-1']) ->order('sort', 'desc')->limit($limit); if (!empty($position)) { $model->where("find_in_set({$position},position)"); } $res = $model->select(); $redis->set($key, json_encode($res, JSON_UNESCAPED_UNICODE), 60); } return $res; } /** * 获取用户信息 * @param $userId * @param $token * @return \app\main\model\object\ReturnObject */ public function getUserInfo($userId, $token) { $userInfo = $this->getUserModel()->getUserInfo($userId); if (empty($userInfo)) { return $this->setCode(ErrorCodeConstants::EXCEPTION)->setMsg('没有找到用户信息')->getReturn(); } if ($userInfo['openid'] == $token) { return $this->setData($userInfo)->getReturn(); } else { return $this->setCode(ErrorCodeConstants::EXCEPTION)->setMsg('用户校验出错,userId与openid不匹配')->getReturn(); } } /** * 获取书籍信息 * @param array $bookParams key为bookId(必须有),value为chapterKey(如果不需要请填空) * @param null $userInfo * @param bool $allRecentBookId 获取用户阅读的所有书籍 * @return \app\main\model\object\ReturnObject * originalBookList 参数$bookParams的key对应的书籍列表,结构与数据库book表相同的书籍列表 * bookList 参数$bookParams的key & 阅读记录的并集 * recentList userId对应的阅读记录,结构与数据库recently表相同的书籍列表 * @throws \Exception */ public function userReadBooksInfo($bookParams, $userInfo = null, $allRecentBookId = false) { $bookIds = array_keys($bookParams); $booksInfo = BookService::instance()->getBookModel()->getBooksInfo($bookIds); $result = ['originalBookList' => $booksInfo]; foreach ($booksInfo as $bookInfo) { $bookId = $bookInfo['id']; $bookInfoItem = $this->bookInfoFormat($bookInfo); $chapterKey = $bookParams[$bookId]; if (empty($chapterKey)) { $bookInfoItem['state'] = BookService::makeBookStatusForClient($bookInfo); } else { $bookInfoItem['state'] = BookService::makeBookStatusForClient($bookInfo, $chapterKey); } $bookResult[$bookId] = $bookInfoItem; } $recentBookIdsFromCps = []; if (!empty($userInfo)) { $recentResult = BookService::instance()->getUserRecentlyRead()->getRecentlyRead(0, 100, $userInfo['id']); $recentList = $recentResult['totalNum'] > 0 ? $recentResult['data'] : []; foreach ($recentList as $recent) { $bookId = $recent['book_id']; if (isset($bookResult[$bookId])) { $bookResult[$bookId]['current_cid'] = $recent['chapter_id']; $bookResult[$bookId]['current_c_name'] = $recent['chapter_name']; $bookResult[$bookId]['action_time'] = $recent['updatetime']; } elseif ($allRecentBookId) { $bookResult[$bookId]['current_cid'] = $recent['chapter_id']; $bookResult[$bookId]['current_c_name'] = $recent['chapter_name']; $bookResult[$bookId]['action_time'] = $recent['updatetime']; $recentBookIdsFromCps[] = $bookId; } } } $booksInfoFromCps = BookService::instance()->getBookModel()->getBooksInfo($recentBookIdsFromCps); foreach ($booksInfoFromCps as $bookInfoFromCps) { $bookId = $bookInfoFromCps['id']; $bookInfoItem = $this->bookInfoFormat($bookInfoFromCps); $bookInfoItem['state'] = BookService::makeBookStatusForClient($bookInfoFromCps); $bookResult[$bookId] = array_merge($bookInfoItem, $bookResult[$bookId]); } $bookResult = empty($bookResult) ? [] : array_values($bookResult); $result['bookList'] = $bookResult; if (isset($recentList)) { $result['recentList'] = $recentList; } return $this->setData($result)->getReturn(); } /** * 格式化书籍对象 * @param $bookInfo 从db或redis中取出的书籍对象 * @return array */ private function bookInfoFormat($bookInfo) { $result = [ 'book_id' => strval($bookInfo['id']), 'book_name' => $bookInfo['name'], 'author' => $bookInfo['author'], 'cover' => $bookInfo['image'], 'chapter_key' => strval($bookInfo['last_chapter_id']), ]; return $result; } /** * @param $userId * @return \app\main\model\object\ReturnObject */ public function getTodaySign($userId) { $todayDate = date('Ymd'); $sign = $this->getSignModel()->setConnect($userId)->where([ 'uid' => $userId, 'createdate' => $todayDate ])->find(); return $this->setData(!empty($sign))->getReturn(); } public function getDefaultBookIds() { $redis = Redis::instance(); if ($redis->exists(ClientApiConstants::DEFAULT_RECOMMAND_KEY)) { $bookIds = $redis->sMembers(ClientApiConstants::DEFAULT_RECOMMAND_KEY); } else { $bookInfos = $this->getClientDefaultRecommandModel() ->where('status', 'normal') ->select(); $bookIds = array_column($bookInfos, 'book_id'); $redis->sAddArray(ClientApiConstants::DEFAULT_RECOMMAND_KEY, $bookIds); } return $this->setData($bookIds)->getReturn(); } /** * 返回书城页的各个配置块的数据 * @param $type * @return array|mixed */ public function pageBlockResource($type) { $redis = Redis::instance(); $boydata = []; $girldata = []; if ($redis->exists('CP:1') && $redis->exists('CP:2')) { $boydata = json_decode($redis->get('CP:1'), true); $girldata = json_decode($redis->get('CP:2'), true); } else { $block = collection(model('ClientManageBlock')->order('page_id asc,weigh desc')->select())->toArray(); foreach ($block as $value) { $blockId = $value['id']; $sources = collection( model('ClientManageBlockResource') ->where('block_id', 'eq', $blockId) ->order('weigh desc') ->limit(4) ->select() )->toArray(); foreach ($sources as $source) { $sourceId = $source['id']; $sourceType = $source['type']; $resRow = []; if ($sourceType == 1) { //书籍 $bookRows = collection( model('ClientManageBlockResource') ->join('book', 'book.id= client_manage_block_resource.book_id') ->join('book_category bc','bc.id = book.book_category_id','LEFT') ->where('client_manage_block_resource.id', 'eq', $sourceId) ->field('bc.name as bc_name,book.book_category_id,book.name,book.author,book.description,book.last_chapter_name,book.last_chapter_id,book.read_num,client_manage_block_resource.*') ->where('book.state=1') ->select() )->toArray(); if (!empty($bookRows)) { $bookRow = $bookRows[0]; $bookRow['read_nums'] = friend_date($bookRow['read_num']); $bookRow['author'] = $bookRow['bc_name']; if (empty($bookRow['url'])) { //重整url @todo url需要重整梳理 $bookRow['url'] = $this->parseAppUrl('bookinfo', ['book_id' => $bookRow['book_id']]); } $resRow = $bookRow; } else { continue; } } else if ($sourceType == 2) { //url $resRow = $urlRow = $source; } else if ($sourceType == 3) { //vip充值 $resRow = $vipRow = $source; $url = Url::build('/clientweb/index/vippopup', '', '', true); $resRow['url'] = $this->parseAppUrl('dialog', ['url' => $url]); } else if ($sourceType == 4) { //活动 $actRows = collection( model('ClientManageBlockResource') ->join('activity activity', 'activity.id= client_manage_block_resource.client_activity_id') ->where('client_manage_block_resource.id', 'eq', $sourceId) ->field('client_manage_block_resource.*') ->where("activity.status='1'") ->where('activity.starttime', '<', time()) ->where('activity.endtime', '>', time()) ->select() )->toArray(); if (!empty($actRows)) { $actRow = $actRows[0]; //重整url $url = Url::build('/clientweb/activity/index', 'id='.$actRow['client_activity_id'], '', true); $actRow['url'] = $this->parseAppUrl('activity', ['url' => $url]); $resRow = $actRow; } else { continue; } } $value['block_resource'][] = $resRow; } if ($value['page_id'] == 1) { $boydata[] = $value; } if ($value['page_id'] == 2) { $girldata[] = $value; } } if (!empty($boydata)) { $redis->set('CP:1', json_encode($boydata, JSON_UNESCAPED_UNICODE)); } if (!empty($girldata)) { $redis->set('CP:2', json_encode($girldata, JSON_UNESCAPED_UNICODE)); } } if ($type == 'boy') { return $boydata; } else { return $girldata; } } /** * 榜单列表 rank1男频 rank2女频 rank0不区分男女 按照idx排序 */ public function rankList($type) { $redis = Redis::instance(); $boydata = []; $girldata = []; if ($redis->exists('CRANK:1') && $redis->exists('CRANK:2') && $redis->exists('CRANK:0')) { $boydata = json_decode($redis->get('CRANK:1'), true); $girldata = json_decode($redis->get('CRANK:2'), true); $idxdata = json_decode($redis->get('CRANK:0'), true); } else { $boydata['click'] = collection( model('Book')->join('book_category bc','bc.id = book.book_category_id','LEFT') ->where(['book.state' => 1, 'book.sex' => 1]) ->field('book.*,bc.name as bc_name') ->order('book.read_num desc') ->limit(10) ->select() )->toArray(); foreach ($boydata['click'] as &$value) { $value['read_nums'] = friend_date($value['read_num']); $value['author'] = $value['bc_name']; } $boydata['idx'] = collection( model('Book')->join('book_category bc','bc.id = book.book_category_id','LEFT') ->where(['book.state' => 1, 'book.sex' => 1]) ->field('book.*,bc.name as bc_name') ->order('book.idx desc') ->limit(10) ->select() )->toArray(); foreach ($boydata['idx'] as &$value) { $value['read_nums'] = friend_date($value['read_num']); $value['author'] = $value['bc_name']; } $girldata['click'] = collection( model('Book')->join('book_category bc','bc.id = book.book_category_id','LEFT') ->where(['book.state' => 1, 'book.sex' => 2]) ->field('book.*,bc.name as bc_name') ->order('book.read_num desc') ->limit(10) ->select() )->toArray(); foreach ($girldata['click'] as &$value) { $value['read_nums'] = friend_date($value['read_num']); $value['author'] = $value['bc_name']; } $girldata['idx'] = collection( model('Book')->join('book_category bc','bc.id = book.book_category_id','LEFT') ->where(['book.state' => 1, 'book.sex' => 2]) ->field('book.*,bc.name as bc_name') ->order('book.idx desc') ->limit(10) ->select() )->toArray(); foreach ($girldata['idx'] as &$value) { $value['read_nums'] = friend_date($value['read_num']); $value['author'] = $value['bc_name']; } $idxdata['idx'] = collection( model('Book')->join('book_category bc','bc.id = book.book_category_id','LEFT') ->where(['book.state' => 1]) ->field('book.*,bc.name as bc_name') ->order('book.idx desc') ->limit(10) ->select() )->toArray(); foreach ($idxdata['idx'] as &$value) { $value['read_nums'] = friend_date($value['read_num']); $value['author'] = $value['bc_name']; } if (!empty($boydata)) { $redis->setex('CRANK:1', $this->ranklivetime, json_encode($boydata, JSON_UNESCAPED_UNICODE)); } if (!empty($girldata)) { $redis->setex('CRANK:2', $this->ranklivetime, json_encode($girldata, JSON_UNESCAPED_UNICODE)); } if (!empty($idxdata)) { $redis->setex('CRANK:0', $this->ranklivetime, json_encode($idxdata, JSON_UNESCAPED_UNICODE)); } } if ($type == 1) { return $boydata; } elseif ($type == 2) { return $girldata; } elseif ($type == 'boy') { return $boydata; } elseif ($type == 'girl') { return $girldata; } else { return $idxdata; } } /* * 主编推荐列表 */ public function recommendList($book_id, $userid = 0) { if($book_id){ $bookInfo = model("book")->BookInfo($book_id); }else{ return false; } $where = []; $where['state'] = '1'; $where['book_category_id'] = $bookInfo['book_category_id']; //最近阅读 $recentList = []; if (!empty($userid)) { $recentList = model('UserRecentlyRead')->getRecentlyRead(0, 10, $userid); } $recentIds[] = $bookInfo['id']; if ($recentList['totalNum'] > 0) { foreach ($recentList['data'] as $v) { $recentIds[] = $v['book_id']; } } if ($recentIds) { $where['id'] = ['not in', $recentIds]; } $pagedata[0]['name'] = "主编推荐"; $pagedata[0]['page_id'] = 1; $pagedata[0]['second_name'] = "主编推荐"; $pagedata[0]['block_resource'] = collection(model("Book") ->where($where) ->order('rand()') ->limit(4) ->select())->toArray(); if($pagedata[0]['block_resource']){ foreach ($pagedata[0]['block_resource'] as &$v){ $v['book_id'] = $v['id']; } } return $pagedata; } /** * @param $packageName * @return \app\main\model\object\ReturnObject * @throws \think\Exception */ public function getPlugin($packageName) { $key = $this->_makeAppHearBookKey($packageName); $resultData = []; $redis = Redis::instance(); if ($redis->exists($key)) { $resultData = json_decode($redis->get($key), true); } else { $result = $this->getHearbookModel() ->where('package_title', $packageName) ->order('version desc') ->find(); if (!empty($result)) { $resultData = $result->toArray(); $redis->set($key, json_encode($resultData)); } } if (empty($resultData)) { return $this->setCode(ErrorCodeConstants::RESULT_EMPTY)->setMsg('没有找到语音包')->getReturn(); } else { return $this->setData($resultData)->getReturn(); } } /** * 组装APP要用的url * @param $urlType * @param $params * @return string */ public function parseAppUrl($urlType, $params) { switch ($urlType) { case "bookinfo": //书籍详情页 $uri = ClientApiConstants::APP_HOST."?page=bookDetail¶m="; $paramsData = [ "bookId" => $params['book_id'], ]; $url = $uri . json_encode($paramsData); break; case "chapter": //阅读器 $uri = ClientApiConstants::APP_HOST."?page=reader¶m="; $paramsData = [ "bookId" => $params['book_id'], ]; if (isset($params['chapter_id'])) { $paramsData['chapterId'] = $params['chapter_id']; } $url = $uri . json_encode($paramsData); break; case "shelf": //书架 $url = ClientApiConstants::APP_HOST."?page=shelf¶m={}"; break; case "account": //个人中心 $url = ClientApiConstants::APP_HOST."?page=account¶m={}"; break; case "book": //书城 $url = ClientApiConstants::APP_HOST."?page=store¶m={}"; break; case "dialog": $url = $params['url']; if (strrpos($url, 'http') === false) { $webHost = Config::get("site.client_web_host"); $url = trim($webHost, '/') . DS. trim($url, '/'); } $paramsData = [ "url" => urlencode($url), ]; $uri = ClientApiConstants::APP_HOST."?page=dialogWebView¶m="; $url = $uri . json_encode($paramsData); break; case "activity": case "url": default: $url = $params['url']; if (strrpos($url, 'http') === false) { $webHost = Config::get("site.client_web_host"); $url = trim($webHost, '/') . DS. trim($url, '/'); } if ($urlType == "activity") { $params['showTitleBar'] = $params['showTitleBar'] ?? true; } $paramsData = [ 'url' => urlencode($url), 'showTitleBar' => $params['showTitleBar'] ?? false ]; $uri = ClientApiConstants::APP_HOST."?page=pageWebView¶m="; $url = $uri . json_encode($paramsData); } return $url; } public function clearHearBookCache($packageName) { $key = $this->_makeAppHearBookKey($packageName); $redis = Redis::instance(); $redis->del($key); } private function _makeAppHearBookKey($packageName) { return sprintf('HB:%s', $packageName); } /** * 获取app版本信息 * @param $versionName * @return \app\main\model\object\ReturnObject * @throws \think\Exception */ public function getAppVersion($versionName) { $key = 'JGUE:' . $versionName; $redis = Redis::instance(); if ($redis->exists($key)) { $res = json_decode($redis->get($key), true); } else { $res = $this->getAppVersionModel()->where('begin_version', '<=', $versionName) ->where('end_version', '>=', $versionName) ->where('status', 'normal') ->order('sort desc') ->find(); $res = empty($res) ? [] : $res->toArray(); $redis->set($key, json_encode($res, JSON_UNESCAPED_UNICODE), 60); } if (!empty($res)) { return $this->setData($res)->getReturn(); } else { return $this->setCode(ErrorCodeConstants::RESULT_EMPTY)->getReturn(); } } }