Book.php 66 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614
  1. <?php
  2. /**
  3. * 前台书籍控制器
  4. */
  5. namespace app\index\controller;
  6. use app\admin\model\ReadNavigation;
  7. use app\common\controller\Frontend;
  8. use app\common\library\Ip;
  9. use app\common\library\Redis;
  10. use app\common\library\Ua;
  11. use app\common\model\GuideWx;
  12. use app\common\service\AdService;
  13. use app\common\service\CampaignService;
  14. use app\common\service\GussNovelService;
  15. use app\common\service\ShareService;
  16. use app\common\service\UserVipExtendService;
  17. use app\common\service\WaterBookService;
  18. use app\main\constants\ActivityConstants;
  19. use app\common\service\VipCpService;
  20. use app\main\constants\AdConstants;
  21. use app\main\constants\AdminConstants;
  22. use app\main\constants\BookConstants;
  23. use app\main\constants\CacheConstants;
  24. use app\main\constants\CampaignConstants;
  25. use app\main\constants\ChannelManageConstants;
  26. use app\main\constants\ErrorCodeConstants;
  27. use app\main\constants\MqConstants;
  28. use app\main\service\AdminService;
  29. use app\main\service\AppGuideService;
  30. use app\main\service\BookService;
  31. use app\main\service\ChannelSpecialManageService;
  32. use app\main\service\ClientAppService;
  33. use app\main\service\ExportFansService;
  34. use app\main\service\FinancialService;
  35. use app\main\service\FloatTipsService;
  36. use app\main\service\LogService;
  37. use app\main\service\SubscripService;
  38. use app\main\service\UrlService;
  39. use app\main\service\UserdotService;
  40. use app\main\service\UserService;
  41. use think\Cache;
  42. use think\Config;
  43. use think\Cookie;
  44. use think\Exception;
  45. use think\exception\HttpException;
  46. use think\Log;
  47. use think\Request;
  48. class Book extends Frontend
  49. {
  50. protected $layout = '';
  51. protected $sex = '1';
  52. protected $is_show_tabbar = 0;
  53. public function _initialize()
  54. {
  55. parent::_initialize();
  56. $userObj = UserService::instance()->getUserInfo();
  57. $channel_id = $userObj->channel_id;
  58. // 猜猜你喜欢
  59. $this->sex = $userObj->sex ?? '1';
  60. $img_reading = '';
  61. $img_recharge = '';
  62. $replysigntxt = '';
  63. if ($book_id = $this->request->request('book_id')) {
  64. $user_id = $userObj->id;
  65. $guideArr = AppGuideService::instance()->getAppGuideInfo($channel_id);
  66. $dycode = ClientAppService::instance()->makeUserRegisterCode($channel_id, $userObj->openid);
  67. if($guideArr){
  68. $img_reading = $guideArr['img_reading'];
  69. $img_recharge = $guideArr['img_recharge'];
  70. $replysigntxt = $guideArr['replysigntxt'];
  71. }
  72. $this->assign('dycode', $dycode);
  73. $cache = UserdotService::instance()->getTrackCache($user_id, $book_id);
  74. if ($cache) {
  75. $track = $cache;
  76. }else{
  77. $track = '{}';
  78. }
  79. $this->assign('track', $track);
  80. $this->assign('gussnovels', []);
  81. }
  82. $this->assign('img_reading', $img_reading);
  83. $this->assign('img_recharge', $img_recharge);
  84. $this->assign('replysigntxt', $replysigntxt);
  85. $showBookShelf = BookService::instance()->showBookShelfFun();
  86. $this->is_show_tabbar = model("ChannelSpecialManage")->isWhite("show_tabbar", $channel_id);
  87. //渠道是否开启了广告功能
  88. /*$isAdPick = model("ChannelSpecialManage")->isWhite("ad_pick", $channel_id);
  89. $this->assign('isAdPick', $isAdPick);*/
  90. $this->assign('ad_rate_chapter', Config::get('site.ad_rate_chapter') ?? 0); //广告点击概率-阅读器中间页
  91. $this->assign('ad_rate_end', Config::get('site.ad_rate_end') ?? 0); //广告点击概率-阅读器章末
  92. $this->assign('ad_rate_menu', Config::get('site.ad_rate_menu') ?? 0); //广告点击概率-呼出菜单
  93. //渠道是否开启了浮窗提醒插屏
  94. $isFloatTips = model("ChannelSpecialManage")->isWhite("float_tips", $channel_id);
  95. $this->assign('isFloatTips', $isFloatTips);
  96. $this->assign('theme', Config::get('site.theme'));
  97. $this->assign('showBookShelf', $showBookShelf);
  98. $this->assign('channel_id', $channel_id);
  99. $this->view->assign('adminconfig',$this->adminconfig);
  100. }
  101. /**
  102. * 书籍列表页
  103. * @param string $type 列表标示
  104. * @return html
  105. */
  106. function list() {
  107. $sex = input('sex');
  108. $type = input('type', 'click');
  109. $description ='暂无该类别图书,换个条件试试看吧!';
  110. switch ($type) {
  111. case 'free':
  112. $title = '限免专区';
  113. $description = '暂无限免小说';
  114. break;
  115. case 'finish':
  116. $title = '完本书籍';
  117. break;
  118. case 'click':
  119. $title = '点击榜';
  120. break;
  121. case 'sell':
  122. $title = '畅销榜';
  123. break;
  124. default:
  125. $title = '书籍列表';
  126. break;
  127. }
  128. $this->assign('title', $title);
  129. $this->assign('description',$description);
  130. $this->assign('sex', $sex);
  131. $this->assign('type', $type);
  132. if (in_array($type, ['click', 'sell'])) {
  133. $this->assign('is_show_tabbar', 0);
  134. $this->assign('tab_choice', 'rank_list');
  135. return $this->view->fetch('rank_list');
  136. }
  137. return $this->view->fetch();
  138. }
  139. /**
  140. * 首页配置的指定区块书籍列表页
  141. * @param int $block_id 区块id
  142. * @return html
  143. */
  144. public function blocklist()
  145. {
  146. $block_id = input('block_id');
  147. $block = model('manage_block')::get($block_id);
  148. $this->assign('block', $block);
  149. return $this->view->fetch();
  150. }
  151. /**
  152. * 书籍列表接口
  153. * @param string $type 榜单类别
  154. * @param int $page 页数
  155. * @return json $books 书籍列表信息 已加redis缓存
  156. */
  157. public function booklistapi()
  158. {
  159. $type = input('type');
  160. $page = input('page', 1);
  161. $user_id = Cookie::get('user_id');
  162. //清水
  163. if ($user_id) {
  164. $userInfo = UserService::instance()->getUserModel()->getUserInfo($user_id);
  165. $channel_id = $userInfo['channel_id'] ?? 0;
  166. if (empty($channel_id)) {
  167. $is_water = false;
  168. } else {
  169. $channel_id = AdminService::instance()->getAdminExtendModel()->getChannelId($channel_id);
  170. $is_water = WaterBookService::instance()->showBook($channel_id, $user_id, Ip::ip());
  171. }
  172. } else {
  173. $is_water = false;
  174. }
  175. $books = model('index')::booklist('', $type, $page, $is_water);
  176. return json($books);
  177. }
  178. /**
  179. * 首页配置的指定区块书籍列表接口
  180. * @param int $block_id 区块id
  181. * @param int $page 页数
  182. * @return json $books 书籍列表信息
  183. */
  184. public function blockbookapi()
  185. {
  186. $block_id = input('block_id');
  187. $page = input('page', 1);
  188. $user_id = Cookie::get('user_id');
  189. //清水
  190. if ($user_id) {
  191. $userInfo = UserService::instance()->getUserModel()->getUserInfo($user_id);
  192. $channel_id = $userInfo['channel_id'] ?? 0;
  193. if (empty($channel_id)) {
  194. $is_water = false;
  195. } else {
  196. $channel_id = AdminService::instance()->getAdminExtendModel()->getChannelId($channel_id);
  197. $is_water = WaterBookService::instance()->showBook($channel_id, $user_id, Ip::ip());
  198. }
  199. } else {
  200. $is_water = false;
  201. }
  202. $data = model('index')::blockbooklist($block_id, $page, $is_water);
  203. return json($data);
  204. }
  205. /**
  206. * 书籍详情页
  207. */
  208. public function info()
  209. {
  210. $book_id = input('book_id');
  211. $user_id = Cookie::get('user_id');
  212. $user = model('User')->getUserInfo($user_id);
  213. //是不是清水
  214. $channelId = AdminService::instance()->getAdminExtendModel()->getChannelId($user['channel_id']);
  215. $isWater = WaterBookService::instance()->showBook($channelId,$user_id,IP::ip());
  216. $book = model('Book')->BookInfo($book_id);
  217. if (empty($book)) {
  218. return $this->statuspage(6); //无此书籍
  219. }
  220. if ($book['state'] == 0) {
  221. return $this->statuspage(3); //本书已下架
  222. }
  223. if ($isWater && (!isset($book['classify_white_list']) || $book['classify_white_list'] != 1)){
  224. return $this->statuspage(3); //清水逻辑 返回下架
  225. }
  226. $book['word_count'] = formatNumber($book['word_count']);
  227. $book['read_num'] = formatNumber($book['read_num']);
  228. $headTenChapters = model('Book')::getChapterLimit($book_id, 0, 9);
  229. if(!isset($headTenChapters)){
  230. return $this->statuspage(6); //当接口出问题获取不到数据,提示暂时无法阅读。
  231. }
  232. $hasread = 0; //默认值
  233. if(Cookie::has('user_id')){
  234. $user_id = Cookie::get('user_id');
  235. $v = 'U-B:' . $user_id . ':' . $book_id;
  236. if($this->redis->exists($v)){
  237. $hasread = 1;
  238. $recent_chapter_id = $this->redis->hget($v, 'chapter_id');
  239. $this->assign("recent_chapter_id", $recent_chapter_id);
  240. }else{
  241. $read_history = model('UserRecentlyRead')->getone($user_id,$book_id);
  242. if(empty($read_history)){
  243. $hasread = 0;
  244. }else{
  245. $hasread = 1;
  246. $this->assign("recent_chapter_id", $read_history['chapter_id']);
  247. }
  248. }
  249. }else{
  250. if(Cookie::has('read')){
  251. $bookinfo = Cookie::get('read', $book_id);
  252. if(empty($bookinfo)){
  253. $hasread = 0;
  254. }else{
  255. $hasread = 1;
  256. $this->assign("recent_chapter_id", $bookinfo['chapter_id']);
  257. }
  258. }
  259. }
  260. $bookFirstChapterInfo = BookService::instance()->getBookChapterInfo($book_id, $book['first_chapter_id']);
  261. /*if ($bookFirstChapterInfo->code == ErrorCodeConstants::EXCEPTION) {
  262. $this->redirect(BookService::instance()->getBookIndexPage($book_id)->data);
  263. } elseif ($bookFirstChapterInfo->code == ErrorCodeConstants::REDIRECT) {
  264. $this->redirect($bookFirstChapterInfo->data);
  265. } elseif ($bookFirstChapterInfo->code == ErrorCodeConstants::REDIRECT_VIEW) {
  266. $bind = $bookFirstChapterInfo->data['bind'];
  267. $template = $bookFirstChapterInfo->data['tpl'];
  268. $this->assign($bind);
  269. return $this->view->fetch($template);
  270. }*/
  271. $firstpart = $secondpart = $thirdpart = $fourthpart = '';
  272. $secondChapterId = $book['first_chapter_id'];
  273. $firstChapterContent = '';
  274. if($bookFirstChapterInfo->code == ErrorCodeConstants::SUCCESS){
  275. if (isset($bookFirstChapterInfo->data['chapter']['next_id'])) {
  276. $secondChapterId = $bookFirstChapterInfo->data['chapter']['next_id'];
  277. }
  278. if (isset($bookFirstChapterInfo->data['chapter']['content'])) {
  279. $firstChapterContent = strip_tags($bookFirstChapterInfo->data['chapter']['content']);
  280. }
  281. $len_content = mb_strlen($firstChapterContent);
  282. $first_len = 120;
  283. $sections = 3;
  284. $firstpart = mb_substr($firstChapterContent, 0, $first_len);
  285. $secondpart = mb_substr($firstChapterContent, $first_len, intval(($len_content - $first_len) / $sections));
  286. $thirdpart = mb_substr($firstChapterContent, intval($first_len + (($len_content - $first_len) / $sections)), intval(($len_content - $first_len) / $sections));
  287. $fourthpart = mb_substr($firstChapterContent, intval($first_len + (($len_content - $first_len) / $sections) *2), intval(($len_content - $first_len) / $sections));
  288. }
  289. //VIP用户判断书籍是否是CP书籍
  290. $showVipCpStyle = false;
  291. if (Cookie::has('user_id') && $this->user->vip_endtime >= time() ) {
  292. if (!VipCpService::instance()->isFreeCpBookForVip($book_id, $this->user->id, $this->user->vip_endtime)) {
  293. $showVipCpStyle = true;
  294. }
  295. }
  296. // 限免书籍,不展示非VIP书籍标记
  297. if($book['free_stime'] <= time() && $book['free_etime'] >= time()){
  298. $showVipCpStyle = false;
  299. }
  300. // 该作者其他书籍
  301. $authorOtherBookId = model('Book')->getBookIdByAuthor($book['author'], $book_id, $this->sex,$isWater);
  302. if($authorOtherBookId){
  303. $authorBook = model('Book')->BookInfo($authorOtherBookId);
  304. }else{
  305. $authorBook = [];
  306. }
  307. $vip_recharge = config('site.vip_recharge');
  308. $this->assign('vip_recharge',$vip_recharge);
  309. $pagedata = BookService::instance()->recommendList($book_id);
  310. $this->view->assign('pagedata', $pagedata);
  311. // 是否已经加入到书架 TRUE | FALSE
  312. $showBookShelf = BookService::instance()->showBookShelfFun();
  313. $this->assign('showBookShelf', $showBookShelf);
  314. if ($showBookShelf) {
  315. $in_shelf = (bool)BookService::instance()->checkBookInShelf($book_id)->data;
  316. $this->assign('in_shelf', $in_shelf);
  317. }
  318. //强关注弹窗
  319. $no_menu = 0;
  320. $isSubscribe = 0;
  321. $guidChapterIdx = 0;
  322. $subscribeTipsInfo = [];
  323. if ($this->adminconfig['subscribe_method'] == 1) {
  324. //强制关注
  325. if ($user && !$user['is_subscribe'] && !$user['subscription_extend']) {
  326. $no_menu = 1;
  327. }
  328. $isSubscribe = !$no_menu;
  329. if ($isSubscribe == 0) {
  330. //未关注
  331. $guidChapterIdx = BookService::instance()->getGuidChapterIdx($book_id, $user['referral_id'])->data;
  332. $subscribeTipsInfo = AdminService::instance()->getQrcode()->data;
  333. if (AdminService::instance()->checkIfGuide()->data) {
  334. //不在强关注 则设置关注章节为0 前端不再弹窗
  335. $guidChapterIdx = 0;
  336. }
  337. //广州地区IP 设置为不弹窗
  338. $city = Ip::city();
  339. if (in_array($city, ['广州市', '深圳市'])) {
  340. if(!model('ChannelSpecialManage')->isWhite(ChannelManageConstants::OPEN_SUBSCRIBE, $this->adminconfig['admin_id'])){
  341. $guidChapterIdx = 0;
  342. }
  343. }
  344. }
  345. }
  346. $this->assign('showVipCpStyle', $showVipCpStyle);
  347. $this->assign('firstpart', $firstpart);
  348. $this->assign('secondpart', $secondpart);
  349. $this->assign('thirdpart', $thirdpart);
  350. $this->assign('fourthpart', $fourthpart);
  351. $this->assign('firstChapterContent', $firstChapterContent);
  352. $this->assign('second_chapter_id', $secondChapterId);
  353. $this->assign('authorBook', $authorBook);
  354. $this->assign('is_subscribe', $isSubscribe);
  355. $this->assign('guideChapterIdx', $guidChapterIdx);
  356. $this->assign('subscribe_tips_info', $subscribeTipsInfo);
  357. $this->assign('subscribe_method', $this->adminconfig['subscribe_method']);
  358. $this->assign('book', $book);
  359. $this->assign('hasread', $hasread);
  360. $this->assign('chapters', $headTenChapters);
  361. $this->assign('gussnovels', $this->_getGussNovels($book_id, $this->sex,$isWater));
  362. $this->assign('custom_title', 1);
  363. return $this->view->fetch();
  364. }
  365. /**
  366. * 书籍目录页
  367. * @param int $book_id 书籍id
  368. * @param int $page 页码
  369. * @param int chapter_id 如果传chapter_id 则直接显示所在page
  370. * @return html
  371. */
  372. public function menu()
  373. {
  374. $book_id = input('book_id');
  375. $page = input('page', 1);
  376. $chapter_id = input('chapter_id');
  377. $fromUserId = input('from_user_id',0);
  378. $shareTime = input('share_time',0);
  379. $book = model('Book')->bookInfo($book_id);
  380. if (empty($book)) {
  381. return $this->statuspage(6); //无此书籍
  382. }
  383. if ($book['state'] == 0) {
  384. return $this->statuspage(3); //本书已下架
  385. }
  386. $page_num = ceil($book['chapter_num'] / 100);
  387. $menuindex = array();
  388. for ($i = 1; $i <= $page_num; $i++) {
  389. $start_num = ($i - 1) * 100;
  390. if ($i < $page_num) {
  391. $end_num = $start_num + 100;
  392. } else {
  393. $end_num = $book['chapter_num'];
  394. }
  395. $menuindex[$i] = array('url' => url('index/book/menu', array('book_id' => $book_id, 'page' => $i,'from_user_id'=>$fromUserId,'share_time'=>$shareTime)), 'name' => 1+$start_num . '-' . $end_num . '章');
  396. }
  397. if($chapter_id && $book_id){
  398. $chapter = model('Book')->getChapterInfo($book_id, $chapter_id);
  399. if($chapter['data']){
  400. $chapter_num = $chapter['data']['idx'];
  401. $page_chapter_idx = ceil($chapter_num / 100);
  402. $page = $page_chapter_idx ? $page_chapter_idx : $page;
  403. }
  404. }
  405. $chapters = model("Book")::getChapterList($book_id, $page, 100);
  406. if ( $chapters['code'] == 100 ){
  407. throw new HttpException(400, '异常错误,请重试');
  408. }
  409. $no_menu = 0;
  410. $isSubscribe = 0;
  411. $guidChapterIdx = 0;
  412. $subscribeTipsInfo = [];
  413. if ($this->adminconfig['subscribe_method'] == 1) {
  414. //强制关注
  415. $user_id = Cookie::get('user_id');
  416. $user = model('User')->getUserInfo($user_id);
  417. if ($user && !$user['is_subscribe'] && !$user['subscription_extend']) {
  418. $no_menu = 1;
  419. }
  420. $isSubscribe = !$no_menu;
  421. if ($isSubscribe == 0) {
  422. //未关注
  423. $guidChapterIdx = BookService::instance()->getGuidChapterIdx($book_id, $user['referral_id'])->data;
  424. $subscribeTipsInfo = AdminService::instance()->getQrcode()->data;
  425. if (AdminService::instance()->checkIfGuide()->data) {
  426. //不在强关注 则设置关注章节为0 前端不再弹窗
  427. $guidChapterIdx = 0;
  428. }
  429. //如果是分享活动,关注章节和二维码优先取分享活动得
  430. if ($fromUserId){
  431. $guidChapterIdx = (int)Config::get('site.share_chapter_num');
  432. $share_default_qrcode = Config::get('site.share_default_qrcode');
  433. if ($share_default_qrcode){
  434. $subscribeTipsInfo['qrcode_image'] = $share_default_qrcode;
  435. }
  436. }
  437. }
  438. //广州地区IP 设置为不弹窗
  439. $city = Ip::city();
  440. if (in_array($city, ['广州市', '深圳市'])) {
  441. if(!model('ChannelSpecialManage')->isWhite(ChannelManageConstants::OPEN_SUBSCRIBE, $this->adminconfig['admin_id'])){
  442. $guidChapterIdx = 0;
  443. }
  444. }
  445. }
  446. $this->assign('from_user_id',$fromUserId);
  447. $this->assign('share_time',$shareTime);
  448. $this->assign('subscribe_tips_info', $subscribeTipsInfo);
  449. $this->assign('subscribe_method', $this->adminconfig['subscribe_method']);
  450. $this->assign('no_menu', $no_menu);
  451. $this->assign('is_subscribe', $isSubscribe);
  452. $this->assign('guideChapterIdx', $guidChapterIdx);
  453. $this->assign('book', $book);
  454. $this->assign('page', $page);
  455. $this->assign('chapter_id', $chapter_id);
  456. $this->assign('menuindex', $menuindex);
  457. $this->assign('menuindexjson', json_encode($menuindex));
  458. $this->assign('chapters', $chapters['data']['data']);
  459. return $this->view->fetch();
  460. }
  461. /**
  462. * 书籍全部章节列表api
  463. * @param int $book_id 书籍id
  464. * @return json
  465. */
  466. public function chapterlistapi()
  467. {
  468. $book_id = input('book_id');
  469. $book = model('book')->bookInfo($book_id);
  470. $chapters = model('book')::getChapterList($book_id, 1, $book['chapter_num']);
  471. $chapterlist = array();
  472. $is_charge_chapter_idx = 20;
  473. foreach ($chapters['data']['data'] as $key => $c) {
  474. if ($key < $is_charge_chapter_idx) {
  475. $is_charge = 0;
  476. } else {
  477. $is_charge = 1;
  478. }
  479. $chapterlist[] = array(
  480. 'chapterId' => $c['id'],
  481. 'chapterName' => $c['name'],
  482. 'is_charge' => $is_charge,
  483. );
  484. }
  485. $data = array(
  486. 'bookId' => $book['id'],
  487. 'bookName' => $book['name'],
  488. 'chapterList' => $chapterlist,
  489. 'headerName' => "章节目录",
  490. 'totalChapters' => $book['chapter_num'],
  491. );
  492. return json($data);
  493. }
  494. /**
  495. * 检查是否开启导航
  496. * @param $channel_id
  497. * @return bool
  498. */
  499. public function checkNav($channel_id)
  500. {
  501. $channel = Config::get('site.app_chapter_nav_channels');
  502. if (!$channel) {
  503. return false;
  504. }
  505. $channels = explode(',', $channel);
  506. if (in_array('*', $channels) || in_array($channel_id, $channels)) {
  507. return true;
  508. }
  509. return false;
  510. }
  511. /**
  512. * @return string
  513. * @throws Exception
  514. */
  515. public function chapter()
  516. {
  517. $book_id = input('book_id');
  518. $user_id = UserService::instance()->getUserInfo()->id;
  519. if (!$book_id) {
  520. $soruceReadLog = BookService::instance()->getUserRecentlyRead()
  521. ->setConnect($user_id)->getRecentlyRead(0, 1, $user_id, true);
  522. if ($soruceReadLog['totalNum'] > 0) {
  523. $book_info = current($soruceReadLog['data']);
  524. $book_id = $book_info['book_id'];
  525. }
  526. }
  527. $kuaifenId = input('uid');
  528. if (!empty($kuaifenId)) {
  529. UserVipExtendService::instance()->saveUserKuaifenId($user_id, $kuaifenId);
  530. }
  531. $chapter_id = input('chapter_id');
  532. $sid = input('sid');
  533. $from_read = input('from_read', 0);
  534. $this->assign('from_read', $from_read);
  535. $this->assign('channel_id', Cookie::get('channel_id') ?? 0);
  536. $this->assign('user_id', Cookie::get('user_id') ?? 0);
  537. $isShow = false;
  538. // 维护书籍阅读数, Redis B-N统计;
  539. $redis_key = CacheConstants::BOOK_USER_READ_COUNT.$book_id;
  540. Redis::instance()->pfAdd($redis_key, Cookie::get('user_id'));
  541. Redis::instance()->expire($redis_key, 86400);
  542. Redis::instance()->hSet('B-N', $book_id, Redis::instance()->pfCount($redis_key));
  543. // $isListenBookOpen 渠道听书开关是否开启
  544. $isListenBookOpen = 0;
  545. if(Cookie::get('channel_id')){
  546. $isListenBookOpen = model("ChannelSpecialManage")->isWhite("listen_book", Cookie::get('channel_id'));
  547. }
  548. $this->assign('isListenBookOpen', $isListenBookOpen);
  549. // $showIntro 是否第一次阅读,用于控制弹出听书引导页
  550. $showIntro = 0 ;
  551. if (Cookie::has('user_id')) {
  552. $res = model('UserRecentlyRead')->getRecentlyRead(0, 1, null, true);
  553. if ($res && $res['data']) {
  554. $showIntro = 1;
  555. }
  556. }
  557. $this->assign('showIntro', $showIntro);
  558. $userInfo = UserService::instance()->getUserInfo();
  559. $channelId = AdminService::instance()->getAdminExtendModel()->getChannelId($userInfo->channel_id);
  560. $isWater = WaterBookService::instance()->showBook($channelId,$userInfo->id,IP::ip());
  561. //书籍与章节信息获取
  562. $bookChapterInfo = BookService::instance()->getBookChapterInfo($book_id, $chapter_id, $sid, $isWater);
  563. if ($bookChapterInfo->code == ErrorCodeConstants::EXCEPTION) {
  564. $this->redirect(BookService::instance()->getBookIndexPage($book_id)->data);
  565. } elseif ($bookChapterInfo->code == ErrorCodeConstants::REDIRECT) {
  566. $this->redirect($bookChapterInfo->data);
  567. } elseif ($bookChapterInfo->code == ErrorCodeConstants::REDIRECT_VIEW) {
  568. $bind = $bookChapterInfo->data['bind'];
  569. $template = $bookChapterInfo->data['tpl'];
  570. $this->assign($bind);
  571. return $this->view->fetch($template);
  572. }
  573. $idx = $bookChapterInfo->data['chapter']['idx'];
  574. $chapter_id = $bookChapterInfo->data['chapter']['id'];
  575. $chapter_name = $bookChapterInfo->data['chapter']['name'];
  576. $is_subscribed = $userInfo->is_subscribe || $userInfo->subscription_extend;
  577. $admin = UserService::instance()->getRunTimeObject()->adminConfig;
  578. $qrcode_image = '';
  579. if ($userInfo->vip_endtime > time()) {
  580. $is_vip = '1';
  581. } else {
  582. $is_vip = '0';
  583. }
  584. $result = [
  585. 'is_subscribed' => $is_subscribed,
  586. 'chapter_name' => $bookChapterInfo->data['chapter']['name'],
  587. 'chapter_content' => $bookChapterInfo->data['chapter']['content'],
  588. 'chapter_idx' => $bookChapterInfo->data['chapter']['idx'],
  589. 'next_link' => $bookChapterInfo->data['next_link'] ? $bookChapterInfo->data['next_link'] . '&from_read=1' : $bookChapterInfo->data['next_link'],
  590. 'pre_link' => $bookChapterInfo->data['pre_link'],
  591. 'book' => $bookChapterInfo->data['book'],
  592. 'subscribe_method' => $admin['subscribe_method'],
  593. 'book_id' => $book_id,
  594. 'chapter_id' => $chapter_id,
  595. 'sid' => $sid,
  596. 'qrcode_image' => $qrcode_image,
  597. 'need_pay' => false,
  598. 'pay_type' => $bookChapterInfo->data['book']['billing_type'],
  599. 'chapter_paid' => "0",
  600. 'is_vip' => $is_vip,
  601. 'add_to_shelf' => (bool)BookService::instance()->checkBookInShelf($book_id)->data,
  602. 'guid_chapter_idx' => 0,
  603. 'is_daofen_end' => 0,
  604. 'subscribe_url' => 0,
  605. 'dd' => 0,
  606. ];
  607. $showBookShelf = BookService::instance()->showBookShelfFun();
  608. $result['show_book_shelf'] = $showBookShelf;
  609. if ($showBookShelf) {
  610. $result['add_to_shelf'] = (bool)BookService::instance()->checkBookInShelf($book_id)->data;
  611. }
  612. $referral_id = UrlService::instance()->getUserReferralId()->data;
  613. //当前章节是否是强制关注的前一章节
  614. $result['is_per_chapter'] = 0;
  615. //添加阅读设置
  616. $result = array_merge($result, BookService::instance()->getReadingSetting()->data);
  617. //支付处理,获取免费章节
  618. $freeChapterIds = FinancialService::instance()->getFreeChapterIdx($book_id);
  619. $result['is_need_pay'] = $is_need_pay = $freeChapterIds != -1 && $bookChapterInfo->data['chapter']['idx'] > $freeChapterIds;
  620. //查看用户是否报名了订阅活动
  621. $actUserInfo = SubscripService::instance()->getActivityUser($userInfo);
  622. //是否需要订阅活动打卡成功的弹窗
  623. $isSubPop = 0;
  624. if ($actUserInfo && date('Ymd') > $actUserInfo['act_date']){//如果已经报名 不需要支付
  625. //打卡
  626. $isSubPop = SubscripService::instance()->insertLog($actUserInfo);
  627. }
  628. //如果是订阅活动分享过来的用户
  629. if ($this->request->has('sub_code') && $subCode = $this->request->param('sub_code')){
  630. SubscripService::instance()->insertUserRelation($subCode,$userInfo->id);
  631. }
  632. if (Input('hide_qrcode')) {
  633. Cookie::set('pop_times', 1);
  634. }
  635. //如果书籍按本收费,且已付费,本章置为已支付
  636. if ($bookChapterInfo->data['book']['billing_type'] == BookConstants::BOOK_BILLING_MODEL_BOOK) {
  637. $where = [
  638. 'user_id' => $userInfo->id,
  639. 'book_id' => $book_id,
  640. 'type' => BookConstants::BOOK_BILLING_MODEL_BOOK
  641. ];
  642. if (FinancialService::instance()->getConsumeModel()->setConnect($userInfo->id)->where($where)->find()) {
  643. $result['chapter_paid'] = '1';
  644. }
  645. }
  646. //需要支付的情况
  647. if ($is_need_pay) {
  648. $result['need_pay'] = true;
  649. $result['chapter_paid'] = '1';
  650. //扣费处理
  651. $payInfo = FinancialService::instance()->getConsumeInfo($book_id, $chapter_id,
  652. $bookChapterInfo->data['chapter']['name']);
  653. //扣费异常
  654. if (in_array($payInfo->code, [ErrorCodeConstants::DB_ERROR_UPDATE, ErrorCodeConstants::EXCEPTION])) {
  655. //todo 扣书币失败的情况
  656. $this->error("异常错误,请稍后重试", BookService::instance()->getBookIndexPage($book_id)->data);
  657. }
  658. //书币不足,重定向到支付
  659. if ($payInfo->code == ErrorCodeConstants::REDIRECT) {
  660. $this->redirect(UrlService::instance()->getPayUrl(get_url_no_port(true), $book_id, $chapter_id)->data);
  661. }
  662. if ($payInfo->data > 0) {
  663. $result['dd'] = 1;
  664. }
  665. }
  666. //关注逻辑
  667. //获取导粉章节
  668. $guid_chapter_idx = BookService::instance()->getGuidChapterIdx($book_id, $referral_id)->data;
  669. $result['guid_chapter_idx'] = $guid_chapter_idx;
  670. //如果是分享链接
  671. $isShareUrl = 0;//是不是分享链接
  672. $isSharePop = 0;//分享链接的弹窗
  673. $fromUserId = $this->request->has('from_user_id') ? $this->request->get('from_user_id'): 0;
  674. $shareTime = $this->request->get('time');
  675. $shareTime = !empty($shareTime) ? $shareTime : time();
  676. // && $userInfo->is_first_unfollow == 2 && $userInfo->subscribe_time == 0
  677. //&& Config::get('site.is_open_share') == "1" 增加拉新活动是否开启
  678. if( $fromUserId && $userInfo->is_subscribe == 0 && Config::get('site.is_open_share') == "1"){
  679. logService::info('被分享者 进入链接'.$userInfo->id.':'.$userInfo->is_first_unfollow);
  680. $shareChapterNum = Config::get('site.share_chapter_num');
  681. $shareParams = "&share_chapter_num=".$shareChapterNum."&time=".$shareTime."&from_user_id=".$fromUserId."&is_first_click=1";
  682. //if($shareTime+300 > time() ){//判断链接是不是过期
  683. //在下一章和上一章地址中拼接参数
  684. $result['next_link'] .= $shareParams;
  685. $result['pre_link'] .= $shareParams;
  686. // 判断是不是第一次点击,是不是首次关注,判断链接是不是过期
  687. if ( $shareTime+24*3600 > time() && $userInfo->is_first_unfollow == 2 && !$this->request->has('is_first_click') ){
  688. ShareService::instance()->ClickShareLink($userInfo->id,$fromUserId,$shareTime);
  689. }
  690. $isShareUrl = 1;
  691. if ( $shareChapterNum-1 <= $idx ){
  692. $isSharePop = 1;
  693. $ewm = AdminService::instance()->getQrcode()->data;
  694. $newCode = Config::get('site.share_default_qrcode');
  695. $result['qrcode_image'] = !empty($newCode) ? $newCode : $ewm['qrcode_image'];
  696. $result['subscribe_url'] = $ewm['subscribe_url'];
  697. $result['is_daofen_end'] = 1;
  698. $this->view->assign('is_show', $isShow);
  699. $this->view->assign('qrcode_image', $result['qrcode_image']);
  700. $this->view->assign('isSharePop', $isSharePop);
  701. $this->view->assign('isShareUrl', $isShareUrl);
  702. $this->view->assign('is_mishu', 0);
  703. $this->assign('showSubscribeTips',0);
  704. LogService::info('分享活动弹窗'.json_encode($result));
  705. // return $this->assign($result)->view->fetch();
  706. }
  707. // }
  708. LogService::info('分享活动-点击001'.$shareParams.'chapter_id'.$chapter_id);
  709. }
  710. $this->view->assign('isSubPop', $isSubPop);
  711. $this->view->assign('isSharePop', $isSharePop);
  712. $this->view->assign('from_user_id', $fromUserId);
  713. $this->view->assign('share_time', $shareTime);
  714. $this->view->assign('isShareUrl', $isShareUrl);
  715. //未关注
  716. $showSubscribeTips = 0;
  717. if (!$is_subscribed && $guid_chapter_idx && $result['subscribe_method'] != AdminConstants::ADMIN_CONFIG_SUBSCRIBE_METHOD_NOT && !$isShareUrl ) {
  718. //获取二维码
  719. $ewm = AdminService::instance()->getQrcode()->data;
  720. $result['subscribe_url'] = $ewm['subscribe_url'];
  721. if ($admin['subscribe_method'] == AdminConstants::ADMIN_CONFIG_SUBSCRIBE_METHOD_FORCE && AdminService::instance()->checkIfGuide()->data) {
  722. $result['subscribe_method'] = AdminConstants::ADMIN_CONFIG_SUBSCRIBE_METHOD_NOT;
  723. }
  724. $result['qrcode_image'] = $ewm['qrcode_image'];
  725. if ($bookChapterInfo->data['chapter']['idx'] >= $guid_chapter_idx) {
  726. //subscribe_url存在即重定向
  727. if ($ewm['subscribe_url']) {
  728. $this->redirect($ewm['subscribe_url']);
  729. }
  730. }
  731. if ($admin['subscribe_method'] == AdminConstants::ADMIN_CONFIG_SUBSCRIBE_METHOD_FORCE && ($guid_chapter_idx - $bookChapterInfo->data['chapter']['idx']) == 1) {
  732. $result['is_per_chapter'] = 1;
  733. }
  734. if ($admin['subscribe_method'] == AdminConstants::ADMIN_CONFIG_SUBSCRIBE_METHOD_FORCE && ($guid_chapter_idx <= $bookChapterInfo->data['chapter']['idx'])) {
  735. $result['is_daofen_end'] = 1;
  736. //添加最近阅读
  737. BookService::instance()->setRecentlyRead($bookChapterInfo->data['chapter']['name'], $chapter_id,
  738. $bookChapterInfo->data['book']['id'], $idx);
  739. //有二维码则不进行弹窗
  740. $this->assign('isAddBackDom', 0);
  741. $this->view->assign('is_mishu', 0);
  742. $this->view->assign('img_times', 0);
  743. //return $this->assign($result)->view->fetch();
  744. }
  745. if ($admin['subscribe_method'] == AdminConstants::ADMIN_CONFIG_SUBSCRIBE_METHOD_GUID && ($guid_chapter_idx <= $bookChapterInfo->data['chapter']['idx'])) {
  746. //二维码已弹出的情况
  747. if (!(Cookie::has('pop_times') && Cookie::get('pop_times') == 1)) {
  748. $result['is_daofen_end'] = 1;
  749. //添加最近阅读
  750. BookService::instance()->setRecentlyRead($bookChapterInfo->data['chapter']['name'], $chapter_id,
  751. $book_id, $idx);
  752. //有二维码则不进行弹窗
  753. $this->assign('isAddBackDom', 0);
  754. $this->view->assign('is_mishu', 0);
  755. $this->view->assign('img_times', 0);
  756. //return $this->assign($result)->view->fetch();
  757. }
  758. }
  759. //广州地区IP 设置为引导关注
  760. $city = Ip::city();
  761. if (in_array($city, ['广州市', '深圳市'])) {
  762. if (!model('ChannelSpecialManage')->isWhite(ChannelManageConstants::OPEN_SUBSCRIBE, $userInfo->channel_id)) {
  763. $result['subscribe_method'] = $admin['subscribe_method'] = AdminConstants::ADMIN_CONFIG_SUBSCRIBE_METHOD_NOT;
  764. }
  765. }
  766. if (in_array($admin['subscribe_method'], [
  767. AdminConstants::ADMIN_CONFIG_SUBSCRIBE_METHOD_FORCE,
  768. AdminConstants::ADMIN_CONFIG_SUBSCRIBE_METHOD_GUID
  769. ]) && $guid_chapter_idx <= $bookChapterInfo->data['chapter']['idx']) {
  770. $showSubscribeTips = 1;
  771. }
  772. }
  773. $this->assign('showSubscribeTips', $showSubscribeTips);
  774. if (UserService::instance()->isLogin()) {
  775. //添加最近阅读
  776. BookService::instance()->setRecentlyRead($bookChapterInfo->data['chapter']['name'], $chapter_id, $book_id,
  777. $idx);
  778. }
  779. //收藏时关注参数
  780. /*if ($admin['qrcode_image']) {
  781. $result['pop_qrcode'] = $admin['qrcode_image'];
  782. } else {
  783. $result['pop_qrcode'] = 'https://open.weixin.qq.com/qr/code?username=' . $admin['json']['authorizer_info']['user_name'];
  784. }*/
  785. // 引导位访问展示打点
  786. AppGuideService::instance()->appGuideViewDot(Cookie::get('channel_id') ?? 0, Cookie::get('user_id') ?? 0,
  787. MqConstants::APP_GUIDE_POSITION_IDX_1);
  788. AppGuideService::instance()->appGuideViewDot(Cookie::get('channel_id') ?? 0, Cookie::get('user_id') ?? 0,
  789. MqConstants::APP_GUIDE_POSITION_IDX_2);
  790. //加文件缓存
  791. if ($this->checkNav($userInfo->channel_id)) {
  792. $navCacheKey = 'CCN';
  793. $nav = Cache::get($navCacheKey);
  794. if ($nav === false) {
  795. $nav = (new ReadNavigation())->where('status', 'normal')->field('title,url')->order('weight',
  796. 'desc')->select();
  797. if ($nav) {
  798. foreach ($nav as $item) {
  799. if (strstr($item['url'], '?')) {
  800. $item['url'] .= '&from=chapter';
  801. } else {
  802. $item['url'] .= '?from=chapter';
  803. }
  804. }
  805. }
  806. Cache::set($navCacheKey, (array)$nav, 600);
  807. }
  808. }
  809. $nav = $nav ?? [];
  810. $export = ExportFansService::instance()->checkFansLead($userInfo->channel_id, $userInfo->id)->data;
  811. if ($export) {
  812. if ($export['status'] == '1' && $export['limittime'] > time()) {
  813. $url = '/index/share/leadpage?id='.$export['id'];
  814. if ($url) {
  815. if ($nav) {
  816. $bakNav = $nav;
  817. $nav = [];
  818. $navTotal = count($bakNav);
  819. if ($navTotal > 3) {
  820. foreach ($bakNav as $k => $item) {
  821. if ($item['title'] == '书架' || $item['title'] == '最近阅读') {
  822. continue;
  823. } else {
  824. $nav[] = [
  825. 'url' => $item['url'],
  826. 'type' => 'txt',
  827. 'title' => $item['title']
  828. ];
  829. }
  830. }
  831. } else {
  832. foreach ($bakNav as $k => $item) {
  833. $nav[] = [
  834. 'url' => $item['url'],
  835. 'type' => 'txt',
  836. 'title' => $item['title']
  837. ];
  838. }
  839. }
  840. }
  841. }
  842. }
  843. $lastNav = [
  844. 'url' => '/index/share/leadpage?id='.$export['id'].'&from=chapter',
  845. 'type' => 'icon',
  846. 'title' => '',
  847. ];
  848. $this->assign('lastNav', $lastNav);
  849. reset($nav);
  850. }
  851. //消耗活动章节计数
  852. if ($campActivity = CampaignService::instance()->getActiveByUser($userInfo->id)) {
  853. $readNumber = $campActivity['read_number'];
  854. $campKey = CampaignConstants::getUserMatchReadKey($userInfo->id);
  855. $readCount = Redis::instance()->get($campKey);
  856. if ($readCount === false || $readCount < $readNumber) {
  857. if (Redis::instance()->incr($campKey) == '1') {
  858. Redis::instance()->expire($campKey, 86400);
  859. }
  860. }
  861. }
  862. //秘书图片弹框
  863. $isOpenMishuTips = 0;
  864. $imgTimes = 1;
  865. if (Config::get('site.is_open_mishu_tip') == 1) {
  866. if ($userInfo && $is_subscribed) {
  867. $isOpenMishuTips = 1;
  868. //是哪张图 第一次还是 第二次弹 或者永久不弹
  869. $mishuTipsNum = Cookie::get("mishu_1_num");
  870. if ($mishuTipsNum >= 2) {
  871. $isOpenMishuTips = 0;
  872. } else {
  873. if ($mishuTipsNum >= 1) {
  874. $imgTimes = 2;
  875. }
  876. }
  877. //判断IP 北京区域不弹
  878. $city = Ip::city();
  879. if (strrpos('北京市', $city) !== false) {
  880. $isOpenMishuTips = 0;
  881. }
  882. if (!in_array(Config::get('site.theme'), ['px', 'sf'])) {
  883. $isOpenMishuTips = 0;
  884. }
  885. }
  886. }
  887. //验证cookie
  888. $float_tip = ['id' => 0];
  889. if (model('ChannelSpecialManage')->isWhite('float_tip', $userInfo->channel_id)) {
  890. $float_tip = FloatTipsService::instance()->getFloatTipsForUser($userInfo->id, $idx, Cookie::get('sell_val'))->data;
  891. if ($float_tip['id'] && $float_tip['book_id'] == $book_id) {
  892. $float_tip['id'] = 0;
  893. }
  894. if ( isset($float_tip['link']) && strstr($float_tip['link'],'http') === false ){
  895. $host = getCurrentDomain($userInfo->channel_id);
  896. $float_tip['link'] = $host.$float_tip['link'];
  897. }
  898. }
  899. $export_fans = ExportFansService::instance()->checkFansReadToExport($userInfo->channel_id, $userInfo->id, $chapter_id)->data;
  900. if ($export_fans) {
  901. $float_tip = ['id' => 0];
  902. }
  903. $this->assign('fans', $export_fans);
  904. $this->assign('float_tip', $float_tip);
  905. $chapter_end = false;
  906. if (model('ChannelSpecialManage')->isWhite('chapter_end', $userInfo->channel_id)) {
  907. $chapter_end = BookService::instance()->getChapterEndRecommendBook($book_id, $idx)->data;
  908. }
  909. $this->assign('chapter_end', $chapter_end);
  910. $this->view->assign('is_mishu', $isOpenMishuTips);
  911. $this->view->assign('img_times', $imgTimes);
  912. $this->assign('nav', $nav);
  913. return $this->assign($result)->view->fetch();
  914. }
  915. /**
  916. * 阅读页的插屏广告
  917. * @return string
  918. * @throws Exception
  919. */
  920. public function ad_chapter()
  921. {
  922. if(!Config::get('template.view_theme')){
  923. $read_theme = 'read_theme_2'; //西瓜
  924. }else{
  925. $read_theme = 'read_theme_1'; //袋鼠 沙发 美书
  926. }
  927. $read_body_fontsize = 'read_body_fontsize_2';
  928. $day_night = '';
  929. if (Cookie::has('cs')) {
  930. $cs['l'] = 1;
  931. $cs = json_decode(Cookie::get('cs'), true); //章节排序 l=1正序 l=2倒序
  932. if ($cs['l'] == 2) {
  933. //$chapterlist['data']['data'] = array_reverse($chapterlist['data']['data']);
  934. }
  935. if ($cs['f']) {
  936. //字号
  937. $read_body_fontsize = 'read_body_fontsize_' . intval($cs['f']);
  938. }
  939. if ($cs['b']) {
  940. //背景色
  941. $read_theme = 'read_theme_' . intval($cs['b']);
  942. }
  943. if ($cs['d'] == 2) {
  944. //白天/夜间 主题
  945. $day_night = 'read_theme_5';
  946. }
  947. }
  948. $this->view->assign('read_body_fontsize', $read_body_fontsize);
  949. $this->view->assign('read_theme', $read_theme);
  950. $this->view->assign('day_night', $day_night);
  951. return $this->view->fetch();
  952. }
  953. /**
  954. * 章节详情页
  955. * @param int $book_id 书籍id
  956. * @param int $chapter_id 章节id
  957. * @return html
  958. */
  959. public function chapter_back()
  960. {
  961. $book_id = input('book_id');
  962. $chapter_id = input('chapter_id');
  963. $user_id = Cookie::get('user_id');
  964. $sid = input('sid');
  965. if (empty($book_id)) {
  966. $this->redirect('/');
  967. }
  968. $bookinfo = model('Book')->BookInfo($book_id);
  969. //调试
  970. if ($this->request->get('debug')) {
  971. echo '<pre>';
  972. var_dump($bookinfo);
  973. echo '<hr />';
  974. }
  975. if (empty($bookinfo)) {
  976. return $this->statuspage(6); //无此书籍
  977. }
  978. if ($bookinfo['state'] == 0) {
  979. return $this->statuspage(3); //本书已下架
  980. }
  981. if (empty($chapter_id)) {
  982. if (Cookie::has('read') && empty($user_id)) {
  983. $readlog = Cookie::get('read');
  984. if (is_array($readlog) && array_key_exists($book_id, $readlog)) {
  985. $chapter_id = $readlog[$book_id]['chapter_id'];
  986. }
  987. }
  988. if ($user_id) {
  989. $readlog = model('UserRecentlyRead')->getone($user_id, $book_id);
  990. if (!empty($readlog)) {
  991. $chapter_id = $readlog['chapter_id'];
  992. }
  993. }
  994. if(empty($chapter_id) && !$sid){
  995. //第一章ID
  996. $chapter_id = $bookinfo['first_chapter_id'];
  997. }
  998. }
  999. if ($sid) {
  1000. if (Cookie::has('read') && empty($user_id)) {
  1001. $readlog = Cookie::get('read');
  1002. if (is_array($readlog) && array_key_exists($book_id, $readlog)) {
  1003. $chapter_id = $readlog[$book_id]['chapter_id'];
  1004. }
  1005. }
  1006. if ($user_id) {
  1007. $readlog = model('UserRecentlyRead')->getone($user_id, $book_id);
  1008. if (!empty($readlog)) {
  1009. $chapter_id = $readlog['chapter_id'];
  1010. }
  1011. }
  1012. if (empty($chapter_id)) {
  1013. $chapter_id = $sid;
  1014. }
  1015. }
  1016. if (empty($chapter_id)) {
  1017. $this->redirect('/index/book/info?book_id=' . $book_id);
  1018. }
  1019. //调试
  1020. if ($this->request->get('debug')) {
  1021. echo '当前书籍ID<hr />';
  1022. echo $book_id;
  1023. echo '--当前章节ID' . $chapter_id;
  1024. echo '<hr />';
  1025. }
  1026. $chapter = model('Book')->getChapterInfo($book_id, $chapter_id);
  1027. //调试
  1028. if ($this->request->get('debug')) {
  1029. var_dump($chapter);
  1030. echo 'urlAgentId:'.$this->urlAgentId;
  1031. echo 'urlChannelId:'.$this->urlChannelId;
  1032. echo 'urlAdminId:'.$this->urlAdminId;
  1033. }
  1034. if ($sid) {
  1035. $chapter['data']['sid'] = $sid;
  1036. } else {
  1037. $chapter['data']['sid'] = '';
  1038. }
  1039. if ($chapter['code']) {
  1040. return $this->statuspage(5); //接口错误跳404
  1041. }
  1042. //处理章节和书籍信息
  1043. $chapter['data']['author'] = $bookinfo['author'];
  1044. $chapter['data']['book_id'] = $bookinfo['id'];
  1045. $chapter['data']['book_name'] = $bookinfo['name'];
  1046. $chapter['data']['image'] = $bookinfo['image'];
  1047. $chapter['data']['description'] = $bookinfo['description'];
  1048. $chapter['data']['last_chapter_name'] = $bookinfo['last_chapter_name'];
  1049. $chapter['data']['last_chapter_id'] = $bookinfo['last_chapter_id'];
  1050. $chapter['data']['is_finish_text'] = $bookinfo['is_finish_text'];
  1051. $chapter['data']['word_count'] = $bookinfo['word_count'];
  1052. $chapter['data']['chapter_num'] = $bookinfo['chapter_num'];
  1053. $chapter['data']['status'] = 4; //返回状态码,0-支付页面;1-需要登录;2-章节错误;3-参数错误;4-成功
  1054. $chapter['data']['read_date'] = time();
  1055. $chapter['data']['state'] = $bookinfo['state'];
  1056. if (empty(strip_tags($chapter['data']['content'])) && !isset($chapter['data']['next_id'])) {
  1057. return $this->statuspage(6); //空章节,并且没有下一章
  1058. }
  1059. if (empty(strip_tags($chapter['data']['content'])) && isset($chapter['data']['next_id'])) {
  1060. return $this->statuspage(4, $chapter['data']); //空章节
  1061. }
  1062. $this->view->assign('statuspage', 0);
  1063. if ($bookinfo['is_finish'] == 1 && empty($chapter['data']['next_id'])) {
  1064. $this->view->assign('statuspage', 2); //完本
  1065. $this->view->assign('statuspage_link', '/index/book/statuspage/code/2/book_id/'.$chapter['data']['book_id']);
  1066. }
  1067. if ($bookinfo['is_finish'] == 0 && empty($chapter['data']['next_id'])) {
  1068. $this->view->assign('statuspage', 1); //连载
  1069. $this->view->assign('statuspage_link', '/index/book/statuspage/code/1/book_id/'.$chapter['data']['book_id']);
  1070. }
  1071. //调取导粉 只有微信环境导粉
  1072. $chapter['data']['alias'] = '';
  1073. $chapter['data']['subscribe_method'] = 0;
  1074. $chapter['data']['daofen'] = '';
  1075. $chapter['data']['true_subscribe_method'] = 0;
  1076. $chapter['data']['need_subscript'] = 0;
  1077. $userinfo = model('user')->setConnect($user_id)->getUserInfo($user_id, 1);
  1078. if(empty($userinfo)){
  1079. $userinfo = [];
  1080. $is_subscribe = 0;
  1081. }else{
  1082. if($userinfo['is_subscribe'] || $userinfo['subscription_extend']){
  1083. $is_subscribe =1;
  1084. }else{
  1085. $is_subscribe =0;
  1086. }
  1087. }
  1088. //获取公众号信息
  1089. if(empty($chapter['data']['alias'])){
  1090. $df_config = $this->adminconfig;
  1091. $chapter['data']['subscribe_method'] = $df_config['subscribe_method'];
  1092. $chapter['data']['qrcode_image'] = $df_config['qrcode_image'];
  1093. $chapter['data']['alias'] = $df_config['json']['authorizer_info']['user_name'];
  1094. if(isset($df_config['subscribe_url']) && $df_config['subscribe_url']){
  1095. $chapter['data']['subscribe_url'] = $df_config['subscribe_url'];
  1096. }
  1097. }
  1098. //引导关注 每天弹一次二维码
  1099. $ewm_pop = 0;
  1100. if($chapter['data']['subscribe_method'] == 2 ){
  1101. if(Cookie::has('tiao') && Cookie::get('tiao')==2){
  1102. $ewm_pop = 1;//已弹出
  1103. }else{
  1104. $ewm_pop = 0;//未弹出
  1105. }
  1106. if(isset($_GET['tiao']) && $_GET['tiao']==2){
  1107. $ewm_pop = 1;//已弹出
  1108. Cookie::set('tiao',2);
  1109. }
  1110. }
  1111. $chapter['data']['next_link'] = '/index/book/chapter?book_id=' . $chapter['data']['book_id'] . '&chapter_id=' . $chapter['data']['next_id'];
  1112. if (Ua::isWeiXin()) {
  1113. $referral_id = UrlService::instance()->getUserReferralId()->data;
  1114. $df_chapter = model('Guide')->isguide($this->urlAgentId, $book_id, $chapter['data']['idx'], $is_subscribe, $referral_id,$this->urlChannelId);
  1115. /*
  1116. * 李聪聪添加的导粉逻辑
  1117. */
  1118. if($chapter['data']['subscribe_method'] == 1){ //如果是强制关注
  1119. $df_config = $this->adminconfig;
  1120. $chapter['data']['true_subscribe_method'] = 1;
  1121. if($this->user->isLogin()){ //如果登陆了没关注
  1122. if($userinfo['is_subscribe'] == 0 && $userinfo['subscription_extend'] ==0 ){
  1123. $chapter['data']['need_subscript'] = 1;
  1124. }
  1125. }else{ //游客
  1126. $chapter['data']['need_subscript'] = 1;
  1127. }
  1128. //判断关注数有没有到上限
  1129. $Scount = 0;
  1130. $redis = Redis::instance();
  1131. $countKey = 'SC:'.$df_config['admin_id'].':'.date('Ymd',$this->time);
  1132. if($redis->exists($countKey)){
  1133. $Scount = intval($redis->get($countKey));
  1134. }
  1135. try{
  1136. if($df_config['fans_count'] !=0 ){ //如果是-1的话,会走随机导粉。如果随机导粉公众号为空,降级为不关注
  1137. if($Scount>=$df_config['fans_count']){ //如果关注数大于设置的关注数上限
  1138. //查看该代理商有没有设置导粉账号
  1139. $guideWx = new GuideWx;
  1140. $qrcodeImage = $guideWx->getGw($df_config['admin_id']); //得到随机一个导粉二维码图片
  1141. if($qrcodeImage){ //如果配置了导粉账号,则随机分配导导粉账号
  1142. if(is_array($qrcodeImage)){
  1143. $chapter['data']['qrcode_image'] = $qrcodeImage['qrcode_image'];
  1144. if(isset($qrcodeImage['subscribe_url']) && $qrcodeImage['subscribe_url']){
  1145. $chapter['data']['subscribe_url'] = $qrcodeImage['subscribe_url'];
  1146. }else{
  1147. if(isset($chapter['data']['subscribe_url'])){
  1148. unset($chapter['data']['subscribe_url']);
  1149. }
  1150. }
  1151. }else{
  1152. if(isset($chapter['data']['subscribe_url'])){
  1153. unset($chapter['data']['subscribe_url']);
  1154. }
  1155. $chapter['data']['qrcode_image'] = $qrcodeImage;
  1156. }
  1157. }else{ //没有配置导粉账号,降级为不关注
  1158. $chapter['data']['need_subscript'] = 0;
  1159. $chapter['data']['subscribe_method'] = 3;
  1160. $df_chapter['clear_data'] = 3;
  1161. }
  1162. }
  1163. }else{
  1164. }
  1165. }catch(Exception $e) {
  1166. throw $e;
  1167. }
  1168. }
  1169. /*
  1170. * 李聪聪添加的导粉逻辑结束
  1171. */
  1172. if ($df_chapter && $ewm_pop == 0) {
  1173. if ($df_chapter['clear_data'] == 1) {
  1174. $chapter['data']['next_id'] = '';
  1175. $chapter['data']['daofen'] = 1;
  1176. // if(isset($chapter['data']['subscribe_url']) && $chapter['data']['subscribe_url']){
  1177. // $this->redirect($chapter['data']['subscribe_url']);
  1178. // }
  1179. }
  1180. if ($df_chapter['clear_data'] == 2) {
  1181. $chapter['data']['next_id'] = '';
  1182. $chapter['data']['pre_id'] = '';
  1183. $chapter['data']['content'] = '';
  1184. $chapter['data']['daofen'] = 1;
  1185. }
  1186. }
  1187. //调试
  1188. if ($this->request->get('debug')) {
  1189. if (isset($df_chapter)) {
  1190. echo '<br />导粉数据打印';
  1191. var_dump($df_chapter);
  1192. }
  1193. }
  1194. //如果关注 则不展示二维码
  1195. if($is_subscribe){
  1196. $chapter['data']['subscribe_method'] = 3;
  1197. }
  1198. }
  1199. //未登录用户阅读记录
  1200. if (empty($user_id)) {
  1201. model('UserRecentlyRead')->recentCookie($book_id, $chapter['data']);
  1202. }
  1203. //调取计费逻辑 包含阅读记录
  1204. $checkfee = new Fee();
  1205. $chapter['data']['need_pay'] = '0';
  1206. $fee_admin_id = $this->urlAgentId?$this->urlAgentId:$this->urlChannelId;
  1207. $fee_res = $checkfee->bookfee($fee_admin_id, $bookinfo, $chapter['data']['name'], $chapter['data']['idx'], $chapter_id, $userinfo);
  1208. if (array_key_exists('isRecharge', $fee_res) && $fee_res['isRecharge'] == 1) {
  1209. //当前章节是否扣费
  1210. $chapter['data']['need_pay'] = 1;
  1211. }
  1212. if ($fee_res['type'] == 2 || $fee_res['type'] == 7) {
  1213. //书币不足,提示充值||游客充值
  1214. if (!empty($user_id)) {
  1215. $params['user_id'] = $user_id;
  1216. } elseif (Cookie::has('visitor')) {
  1217. $params['visitor'] = Cookie::get('visitor');
  1218. }
  1219. $params['book_id'] = $book_id;
  1220. $params['chapter_id'] = $chapter_id;
  1221. $redirect_url = get_url_no_port(true);
  1222. $admin_info = model('adminConfig')->getAdminInfoAll($this->urlAdminId);
  1223. if(!empty($admin_info) && $admin_info['appid']){
  1224. $redirect_url = str_replace($this->adminconfig['appid'],$admin_info['appid'],$redirect_url);
  1225. }
  1226. $params['redirect'] = $redirect_url;
  1227. //Log::write($redirect_url,'cctest3');
  1228. $info = model("AdminConfig")->getAdminInfoAll($this->urlChannelId);
  1229. //有菜单支付域名时,跳转菜单支付域名
  1230. $menuophost = $info['menuophost'] ?? null;
  1231. $menuwxpay_host = $info['menuwxpay_host'] ?? null;
  1232. if($menuophost && $menuwxpay_host && $menuophost == getCurrentOphost()){
  1233. //Log::write(Config::get('site.scheme') . '://' . $info['menuwxpay_host'] . '/index/recharge/pay?' . http_build_query($params),'cctestBook1');
  1234. $this->redirect(Config::get('site.scheme') . '://' . $info['menuwxpay_host'] . '/index/recharge/pay?' . http_build_query($params));
  1235. }else{
  1236. //Log::write(Config::get('site.scheme') . '://' . $info['wxpay_pay_host'] . '/index/recharge/pay?' . http_build_query($params),'cctestBook2');
  1237. $this->redirect(Config::get('site.scheme') . '://' . $info['wxpay_pay_host'] . '/index/recharge/pay?' . http_build_query($params));
  1238. }
  1239. }
  1240. if (empty($chapter['data']['pre_id'])) {
  1241. $chapter['data']['pre_link'] = "javascript:consoleMain('已经是第一章了');";
  1242. } else {
  1243. $chapter['data']['pre_link'] = '/index/book/chapter?book_id=' . $chapter['data']['book_id'] . '&chapter_id=' . $chapter['data']['pre_id'];
  1244. }
  1245. //章节列表
  1246. //$chapterlist = model('book')::getChapterList($chapter['data']['book_id']);
  1247. // switch (Config::get('template.view_theme')){
  1248. // case 'qy':
  1249. // $read_theme = 'read_theme_1'; //袋鼠
  1250. // break;
  1251. // default:
  1252. // $read_theme = 'read_theme_2'; //西瓜
  1253. // }
  1254. if(!Config::get('template.view_theme')){
  1255. $read_theme = 'read_theme_2'; //西瓜
  1256. }else{
  1257. $read_theme = 'read_theme_1'; //袋鼠 沙发 美书
  1258. }
  1259. $read_body_fontsize = 'read_body_fontsize_2';
  1260. $day_night = '';
  1261. if (Cookie::has('cs')) {
  1262. $cs['l'] = 1;
  1263. $cs = json_decode(Cookie::get('cs'), true); //章节排序 l=1正序 l=2倒序
  1264. if ($cs['l'] == 2) {
  1265. //$chapterlist['data']['data'] = array_reverse($chapterlist['data']['data']);
  1266. }
  1267. if ($cs['f']) {
  1268. //字号
  1269. $read_body_fontsize = 'read_body_fontsize_' . intval($cs['f']);
  1270. }
  1271. if ($cs['b']) {
  1272. //背景色
  1273. $read_theme = 'read_theme_' . intval($cs['b']);
  1274. }
  1275. if ($cs['d'] == 2) {
  1276. //白天/夜间 主题
  1277. $day_night = 'read_theme_5';
  1278. }
  1279. }
  1280. if (Ua::isWeiXin() && isset($df_chapter) && !empty($df_chapter) && $ewm_pop == 0) {
  1281. if ($df_chapter['clear_data'] == 2 && isset($chapter['data']['subscribe_url']) && $chapter['data']['subscribe_url']) {
  1282. $this->redirect($chapter['data']['subscribe_url']);
  1283. }
  1284. }
  1285. $this->view->assign('read_body_fontsize', $read_body_fontsize);
  1286. $this->view->assign('read_theme', $read_theme);
  1287. $this->view->assign('day_night', $day_night);
  1288. //$this->view->assign('chapterlist', $chapterlist['data']['data']);
  1289. $this->view->assign('chapter', $chapter['data']);
  1290. //调试
  1291. if ($this->request->get('debug')) {
  1292. echo '输出章节数据';
  1293. var_dump($chapter);
  1294. echo '输出未登录阅读记录';
  1295. var_dump(Cookie::get('read'));
  1296. }
  1297. $this->view->assign('signstr','sign'.Date('Ymd',time()));
  1298. //dump($chapter['data']);die;
  1299. return $this->view->fetch();
  1300. }
  1301. /**
  1302. * 状态页
  1303. * $code 1 正在码字| 2 已完结| 3 已下架| 4 章节内容为空| 5 404[并不处理] | 6 提示此本书暂时无法阅读
  1304. * $chapter
  1305. * $book_id
  1306. */
  1307. public function statuspage($code, $chapter = [],$book_id='')
  1308. {
  1309. if (strpos($book_id,'&')){
  1310. $book_id = substr($book_id,0,strpos($book_id,'&'));
  1311. }
  1312. switch ($code) {
  1313. case 1:
  1314. $template = 'typing';
  1315. $this->ranklist($book_id);
  1316. break;
  1317. case 2:
  1318. $template = 'finish';
  1319. $this->ranklist($book_id);
  1320. break;
  1321. case 3:
  1322. $template = 'forbiddenread';
  1323. break;
  1324. case 4:
  1325. $template = 'nocontent';
  1326. $chapter['next_link'] = '/index/book/chapter?book_id=' . $chapter['book_id'] . '&chapter_id=' . $chapter['next_id'];
  1327. $this->view->assign('chapter', $chapter);
  1328. break;
  1329. case 5:
  1330. $template = '404';
  1331. break;
  1332. case 6:
  1333. $template = 'nobook';
  1334. break;
  1335. default:
  1336. $template = 'typing';
  1337. $this->ranklist($book_id);
  1338. }
  1339. $bookinfo = [];
  1340. if($book_id){
  1341. $bookinfo = model('Book')->BookInfo($book_id);
  1342. if($bookinfo){
  1343. if($bookinfo['recommand_book_id']){
  1344. $recmooand = model('Book')->BookInfo($bookinfo['recommand_book_id']);;
  1345. $bookinfo['recommand_book_image'] =$recmooand['image'];
  1346. $bookinfo['recommand_book_name'] =$recmooand['name'];
  1347. }
  1348. }else{
  1349. return $this->statuspage(6);
  1350. }
  1351. }
  1352. $this->view->assign('book',$bookinfo);
  1353. return $this->view->fetch('public/' . $template);
  1354. }
  1355. /*
  1356. * 为你推荐
  1357. * 调用页面-最近阅读页??
  1358. * 调用页面-完结页
  1359. * 调用页面-作者码字页
  1360. * 从当前列表去掉当前书籍
  1361. */
  1362. public function ranklist($book_id){
  1363. $sex_type = model('User')->getUserSex($this->user->sex,$this->adminconfig,true);
  1364. $channel_id = AdminService::instance()->getAdminExtendModel()->getChannelId($this->user->channel_id);
  1365. $isWater = WaterBookService::instance()->showBook($channel_id,$this->user->id,IP::ip());
  1366. $ranklist = BookService::instance()->ranklist($sex_type, $isWater);
  1367. if($book_id){
  1368. foreach ($ranklist['idx'] as $k=>$value){
  1369. if($value['id']==$book_id){
  1370. unset($ranklist['idx'][$k]);
  1371. }
  1372. }
  1373. }
  1374. $this->view->assign('ranklist', $ranklist);
  1375. $this->assign('gussnovels', $this->_getGussNovels($book_id, $this->sex, $isWater));
  1376. }
  1377. /**
  1378. * 关注子公众号302跳转
  1379. */
  1380. public function sub(){
  1381. $userId = Cookie::get('user_id');
  1382. if(empty($userId)){
  1383. $userId = $this->user->id;
  1384. }
  1385. $user = UserService::instance()->getUserModel()->getUserInfo($userId);
  1386. // $user = model('User')->setConnect($userId)->where('id',$userId)->find();
  1387. try {
  1388. $recetly = model('UserRecentlyRead')->getRecentlyRead(0, 1, null, true);
  1389. if ($recetly['totalNum'] > 0) {
  1390. $book_name = $recetly['data'][0]['book_name'];
  1391. $book_id = $recetly['data'][0]['book_id'];
  1392. } else {
  1393. $rankList = controller('index/index')->ranklist($user['sex'] ?? 0);
  1394. $book_name = $rankList['idx'][0]['name'];
  1395. $book_id = $rankList['idx'][0]['id'];
  1396. }
  1397. if ($book_name && $book_id) {
  1398. $book_url = getCurrentDomain($this->adminconfig['admin_id'],'/index/book/chapter',['book_id'=>$book_id]);
  1399. header('Location:'.$book_url); //302跳转到最近阅读的书
  1400. }
  1401. } catch (\Exception $exception) {
  1402. Log::error('微信子公众号关注获取最近阅读记录失败!');
  1403. }
  1404. }
  1405. /**
  1406. * 保存书籍
  1407. * @param $url
  1408. * @param $zone
  1409. * @param $adid
  1410. * @param $book_id
  1411. * @return \think\response\Json
  1412. */
  1413. public function saveBookInfo($url, $zone, $adid, $book_id)
  1414. {
  1415. $track_ids = [
  1416. 'pre_id' => $this->request->post('pre_id') ?? '',
  1417. 'current_id' => $this->request->post('current_id') ?? '',
  1418. ];
  1419. return UserdotService::instance()->saveTrackInfo($url, $zone, $adid, $book_id, $track_ids);
  1420. }
  1421. public function getreturnchapterbook()
  1422. {
  1423. return BookService::instance()->getReturnRecommandBook();
  1424. }
  1425. /**
  1426. * 测书场景(猜你喜欢)
  1427. * @param $book_id 排重书籍ID
  1428. * @param string $sex
  1429. * @param $isWater
  1430. * @return array
  1431. */
  1432. private function _getGussNovels($book_id, $sex = '1', $isWater=false)
  1433. {
  1434. if(empty($sex)){
  1435. $sex = '1';
  1436. }
  1437. $novels = GussNovelService::instance()->getLikedNovels($sex, 5,$isWater);
  1438. //过滤书籍 确保书籍唯一,且不包含 当前书籍
  1439. $bookList = [];
  1440. foreach ($novels as $novel) {
  1441. if ($book_id != $novel['book_id']) {
  1442. $bookList[] = $novel;
  1443. }
  1444. }
  1445. return $bookList;
  1446. }
  1447. /**
  1448. * 书架列表
  1449. */
  1450. public function shelf()
  1451. {
  1452. $this->assign('is_show_tabbar', $this->is_show_tabbar);
  1453. $this->assign('tab_choice', 'bookshelf');
  1454. if (Cookie::has('user_id')) {
  1455. $this->view->assign('login',1);//登录
  1456. }else {
  1457. $this->view->assign('login',0);//未登录
  1458. }
  1459. $result = BookService::instance()->getBookShelf();
  1460. if ($result->code == ErrorCodeConstants::SUCCESS) {
  1461. $this->view->assign('shelflist', $result->data);
  1462. $this->view->assign('totalNum', count($result->data));
  1463. return $this->view->fetch();
  1464. } else {
  1465. $this->error($result->msg);
  1466. }
  1467. }
  1468. public function setNextPageCache()
  1469. {
  1470. $bookId = Request::instance()->request('book_id');
  1471. $userId = Cookie::get('user_id');
  1472. $cacheKey = CacheConstants::getBookSubCache($userId);
  1473. Redis::instance()->setex($cacheKey, 3600, $bookId);
  1474. $this->success();
  1475. }
  1476. }