Book.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: lts
  5. * Date: 2019-04-03
  6. * Time: 19:49
  7. */
  8. namespace app\clientappapi\controller;
  9. use app\common\controller\ClientApi;
  10. use app\main\constants\BookConstants;
  11. use app\main\constants\ClientApiConstants;
  12. use app\main\helper\ArrayHelper;
  13. use app\main\service\BookService;
  14. use app\main\constants\ErrorCodeConstants;
  15. use app\main\service\FinancialService;
  16. use app\main\service\ClientAppService;
  17. use app\main\service\LogService;
  18. use think\Exception;
  19. class Book extends ClientApi
  20. {
  21. /**
  22. * 章节订购接口
  23. * @return mixed
  24. */
  25. public function chapterorder()
  26. {
  27. $this->checkParamRequired(['bookId', 'type'], false);
  28. $bookId = $this->params['bookId'];
  29. $chapterId = empty($this->params['chapterId']) ? 0 : $this->params['chapterId'];
  30. $type = $this->params['type'];
  31. $bookInfo = BookService::instance()->getBookModel()->BookInfo($bookId);
  32. if (!$bookInfo) {
  33. $this->error("书籍不存在");
  34. }
  35. //书籍已下架
  36. if ($bookInfo['state'] == BookConstants::BOOK_STATE_OFF_SALE) {
  37. $result['state'] = ClientApiConstants::CHAPTER_STATE_BOOK_OFF_SALE;
  38. $this->info($result);
  39. }
  40. $needCostFee = true;
  41. $chapterInfoResult = BookService::instance()->getBookChapterInfoForClient($bookInfo, $chapterId, $type);
  42. if ($chapterInfoResult->code == ErrorCodeConstants::SUCCESS) {
  43. $chapterInfo = $chapterInfoResult->data;
  44. $result = [
  45. 'chapter' => [
  46. 'chapter_id' => $chapterInfo['id'],
  47. 'chapter_name' => $chapterInfo['name'],
  48. 'chapter_index' => $chapterInfo['idx'],
  49. 'book_id' => $bookId,
  50. 'next_chapter' => $chapterInfo['next_id'],
  51. 'pre_chapter' => $chapterInfo['pre_id'],
  52. 'content' => $chapterInfo['content'] ?: '',
  53. ]
  54. ];
  55. if (isset($chapterInfo['status'])) {
  56. $result['chapter']['state'] = $chapterInfo['status'];
  57. }
  58. } elseif ($chapterInfoResult->code == ClientApiConstants::CHAPTER_NOT_EXIST && in_array($type,
  59. [ClientApiConstants::GET_CHAPTER_TYPE_PRE, ClientApiConstants::GET_CHAPTER_TYPE_NEXT])) {
  60. if ($bookInfo['is_finish'] == '1') {//完本
  61. $result['state'] = ClientApiConstants::CHAPTER_STATE_NO_NEXT_FINISHED;
  62. } else {
  63. $result['state'] = ClientApiConstants::CHAPTER_STATE_NO_NEXT_SERIALIZING;
  64. }
  65. $needCostFee = false;
  66. } elseif ($chapterInfoResult->code == ClientApiConstants::CHAPTER_NOT_EXIST) {
  67. $needCostFee = false;
  68. $result['state'] = ClientApiConstants::CHAPTER_STATE_NO_CONTENT;
  69. } else {
  70. $this->error($chapterInfoResult->msg, $chapterInfoResult->code);
  71. }
  72. if ($needCostFee) {
  73. $feeResult = FinancialService::instance()->feeChapterForClient($this->userInfo, $bookInfo, $chapterInfo);
  74. if ($feeResult->code == ErrorCodeConstants::SUCCESS) {
  75. $feeInfo = $feeResult->data;
  76. if (!isset($result['chapter']['state'])) {
  77. $result['chapter']['state'] = $feeInfo['orderState'];
  78. }
  79. if (isset($feeInfo['cost'])) {
  80. $result['chapter']['cost'] = $feeInfo['cost'];
  81. }
  82. $result['state'] = $feeInfo['state'];
  83. if ($feeInfo['state'] == ClientApiConstants::CHAPTER_STATE_BALANCE_NOT_ENOUGH) {
  84. $result['billing_type'] = $bookInfo['billing_type'];
  85. $result['price'] = $feeInfo['cost'];
  86. }
  87. } else {
  88. $this->error($feeResult->msg, $feeResult->code);
  89. }
  90. }
  91. $this->info($result);
  92. }
  93. /**
  94. * 获取书籍目录接口
  95. * @return mixed
  96. */
  97. public function getchapters()
  98. {
  99. $this->checkParamRequired('bookId');
  100. $bookId = $this->params['bookId'];
  101. $bookInfo = BookService::instance()->getBookModel()->BookInfo($bookId);
  102. if (!$bookInfo) {
  103. $this->error('书籍不存在');
  104. }
  105. $chaptersResult = BookService::instance()->getChapterListForClient($bookId);
  106. if ($chaptersResult->code == ErrorCodeConstants::SUCCESS) {
  107. $chapters = $chaptersResult->data;
  108. $chapterList = [];
  109. foreach ($chapters as $chapter) {
  110. $chapterList[] = [
  111. 'chapter_id' => $chapter['id'],
  112. 'chapter_name' => $chapter['name'],
  113. 'chapter_index' => $chapter['idx'],
  114. ];
  115. }
  116. $lastChapter = end($chapterList);
  117. $result = ['chapter_list' => $chapterList];
  118. if ($lastChapter) {
  119. $result['chapter_key'] = $lastChapter['chapter_id'];
  120. }
  121. $result['chapter_key'] = strval($bookInfo['last_chapter_id']);
  122. $this->success('', $result);
  123. } else {
  124. $this->error($chaptersResult->msg);
  125. }
  126. }
  127. /**
  128. * 获取书籍信息接口
  129. */
  130. public function getbookinfo()
  131. {
  132. $this->checkParamRequired('bookId');
  133. $bookId = $this->params['bookId'];
  134. $recommendBookSize = $this->params['recommendBookSize'] ?? 9;
  135. $result = [];
  136. $bookInfoResult = ClientAppService::instance()->userReadBooksInfo([$bookId => ''], $this->userInfo);
  137. if ($bookInfoResult->code == ErrorCodeConstants::SUCCESS) {
  138. if (count($bookInfoResult->data['originalBookList']) > 0 && count($bookInfoResult->data['bookList']) > 0) {
  139. $originalBook = current($bookInfoResult->data['originalBookList']);
  140. $book = current($bookInfoResult->data['bookList']);
  141. $bookInfo = [
  142. 'book_id' => $originalBook['id'],
  143. 'book_name' => $originalBook['name'],
  144. 'author' => $originalBook['author'],
  145. 'cover' => $originalBook['image'],
  146. 'state' => $book['state'],
  147. 'current_cid' => $book['current_cid'] ?? 0,
  148. 'action_time' => $book['action_time'] ?? 0,
  149. 'chapter_key' => $book['chapter_key'],
  150. 'is_finish' => $originalBook['is_finish'],
  151. 'word_count' => formatNumber($originalBook['word_count']) . '字',
  152. 'read_num' => formatNumber($originalBook['read_num']),
  153. 'category_text' => $originalBook['category_text'],
  154. 'description' => $originalBook['description'],
  155. 'last_chapter_id' => $originalBook['last_chapter_id'],
  156. 'last_chapter_name' => $originalBook['last_chapter_name'],
  157. 'last_chapter_utime' => $originalBook['last_chapter_utime'],
  158. 'chapter_num' => $originalBook['chapter_num'],
  159. ];
  160. $result['book_info'] = $bookInfo;
  161. } else {
  162. throw new Exception('没有找到书籍信息,bookID:' . $bookId);
  163. }
  164. } else {
  165. throw new Exception($bookInfoResult->msg);
  166. }
  167. $sex = 0;
  168. if (!empty($this->userInfo)) {
  169. $sex = $this->userInfo['sex'];
  170. }
  171. $recommendBookIds = BookService::instance()->getRecommendBookIdsForClient($sex, $recommendBookSize);
  172. $needBookIds = array_diff($recommendBookIds, [$bookId]);
  173. $needBookIds = array_slice($needBookIds, 0, 8);
  174. $recommendBookIdsParams = [];
  175. foreach ($needBookIds as $recommendBookId) {
  176. $recommendBookIdsParams[$recommendBookId] = '';
  177. }
  178. $recommendBooksInfoResult = ClientAppService::instance()->userReadBooksInfo($recommendBookIdsParams,
  179. $this->userInfo);
  180. if ($recommendBooksInfoResult->code != ErrorCodeConstants::SUCCESS) {
  181. throw new Exception($recommendBooksInfoResult->msg);
  182. }
  183. $result['recommend_book_list'] = $recommendBooksInfoResult->data['bookList'];
  184. $this->info($result);
  185. }
  186. /**
  187. * 书架接口
  188. */
  189. public function syncbookshelf()
  190. {
  191. $this->checkParamRequired('json');
  192. $bookParamsStr = $this->params['json'];
  193. $bookParamsList = json_decode($bookParamsStr, true);
  194. $userId = $this->userInfo['id'] ?? null;
  195. $bookParams = [];
  196. $recentUpBookIds = [];
  197. $recentDelBookIds = [];
  198. foreach ($bookParamsList as $bookParam) {
  199. $bookId = $bookParam['bookId'];
  200. $bookParams[$bookId] = $bookParam['chapterKey'];
  201. }
  202. if (!empty($this->userInfo)) {//登录后的用户处理更新与删除
  203. foreach ($bookParamsList as $bookParam) {
  204. $bookId = $bookParam['bookId'];
  205. switch ($bookParam['operate']) {
  206. case ClientApiConstants::RECENT_OPERATE_UPDATE:
  207. $recentUpBookIds[] = $bookId;
  208. break;
  209. case ClientApiConstants::RECENT_OPERATE_DELETE:
  210. $recentDelBookIds[] = $bookId;
  211. break;
  212. default:
  213. break;
  214. }
  215. }
  216. }
  217. //获取书籍信息和最近阅读信息
  218. $booksInfoResult = ClientAppService::instance()->userReadBooksInfo($bookParams, $this->userInfo, true);
  219. if ($booksInfoResult->code != ErrorCodeConstants::SUCCESS) {
  220. throw new Exception($booksInfoResult->msg);
  221. }
  222. $bookList = $booksInfoResult->data['bookList'];
  223. $originalBookList = $booksInfoResult->data['originalBookList'];
  224. $recentList = isset($booksInfoResult->data['recentList']) ? $booksInfoResult->data['recentList'] : [];
  225. //更新最近阅读
  226. foreach ($recentUpBookIds as $recentUpBookId) {
  227. //待更新书籍的章节列表
  228. $chaptersResult = BookService::instance()->getChapterListForClient($recentUpBookId);
  229. if ($chaptersResult->code != ErrorCodeConstants::SUCCESS) {
  230. LogService::error(sprintf('更新最近阅读失败,userId:%s,bookId:%s,msg:%s', $userId, $recentUpBookId,
  231. $chaptersResult->msg));
  232. continue;
  233. }
  234. $chapterList = $chaptersResult->data;
  235. //从输入参数中获取待更新书籍对象
  236. $bookUpParamsItem = ArrayHelper::array_column_search($bookParamsList, 'bookId', $recentUpBookId);
  237. //从章节列表获取用户阅读最新章节的"阅读记录对象"
  238. $chapterItem = ArrayHelper::array_column_search($chapterList, 'id', $bookUpParamsItem['currentCid']);
  239. if (empty($chapterItem)) {
  240. LogService::error(sprintf('没有找到书籍指定章节,bookId:%s,currentCid:%s', $recentUpBookId,
  241. $bookUpParamsItem['currentCid']));
  242. continue;
  243. }
  244. //从数据库获取待更新书籍原始对象
  245. // $bookItem = ArrayHelper::array_column_search($originalBookList, 'id', $recentUpBookId);
  246. $upRecentResult = BookService::instance()->setRecentlyRead($chapterItem['name'], $chapterItem['id'],
  247. $recentUpBookId, $userId, $chapterItem['idx']);
  248. if ($upRecentResult->code != ErrorCodeConstants::SUCCESS) {
  249. $this->error($upRecentResult->msg, $upRecentResult->code);
  250. }
  251. #region 更新阅读记录后,将最新的阅读章节信息返回
  252. foreach ($bookList as &$orgBookItem) {
  253. if ($recentUpBookId == $orgBookItem['book_id']) {
  254. $orgBookItem['current_cid'] = $chapterItem['id'];
  255. $orgBookItem['current_c_name'] = $chapterItem['name'];
  256. $orgBookItem['action_time'] = strval(time());
  257. }
  258. }
  259. #endregion
  260. }
  261. $delRecentIds = [];
  262. $delRecentBookIds = [];
  263. //删除最近阅读记录
  264. foreach ($recentDelBookIds as $recentDelBookId) {
  265. $recentItem = ArrayHelper::array_column_search($recentList, 'book_id', $recentDelBookId);
  266. #region 在返回的书籍列表中删除需要在阅读记录删除的书籍信息
  267. foreach ($bookList as $key => $item) {
  268. if ($item['book_id'] == $recentDelBookId) {
  269. unset($bookList[$key]);
  270. break;
  271. }
  272. }
  273. #endregion
  274. if (empty($recentItem)) {
  275. LogService::error(sprintf('删除最近阅读失败,用户没有阅读过这本书,userId:%s,bookIds:%s', $userId, $recentDelBookId));
  276. continue;
  277. }
  278. $delRecentIds[] = $recentItem['id'];
  279. $delRecentBookIds[] = $recentItem['book_id'];
  280. }
  281. if (count($delRecentIds) > 0 && count($delRecentBookIds) > 0) {
  282. $delRecentResult = BookService::instance()->removeRecentlyRead($delRecentIds, $delRecentBookIds, $userId);
  283. if ($delRecentResult->code != ErrorCodeConstants::SUCCESS) {
  284. LogService::error(sprintf('删除最近阅读失败,userId:%s,msg:%s', $userId, $delRecentResult->msg));
  285. }
  286. }
  287. foreach ($bookList as &$bookItem) {
  288. if (empty($bookItem['action_time'])) {
  289. $paramItem = ArrayHelper::array_column_search($bookParamsList, 'bookId', $bookItem['book_id'], true);
  290. $bookItem['action_time'] = strval($paramItem['actionTime']);
  291. }
  292. }
  293. $bookList = array_values($bookList);
  294. $result['book_list'] = $bookList;
  295. $this->info($result);
  296. }
  297. /**
  298. * 书籍详情页推荐书籍接口
  299. * @throws Exception
  300. */
  301. public function recommendbooks()
  302. {
  303. $this->checkParamRequired(['bookIds', 'size']);
  304. $strExcludeBookIds = $this->params['bookIds'];
  305. $excludeBookIds = explode(',', $strExcludeBookIds);//需要排除的书籍id列表
  306. $size = $this->params['size'];
  307. $sex = 0;
  308. if (!empty($this->userInfo)) {
  309. $sex = $this->userInfo['sex'];
  310. }
  311. //推荐书籍id列表,获取的数量是客户端展示数量的3倍,用于随机处理。
  312. $recommendBookIds = BookService::instance()->getRecommendBookIdsForClient($sex, $size * 3);
  313. //过滤需要排除的书籍id列表
  314. $needBookIds = array_diff($recommendBookIds, $excludeBookIds);
  315. //随机获取书籍id的key
  316. $needBookKeys = array_rand($needBookIds, $size);
  317. $needBookResIds = [];
  318. foreach ($needBookKeys as $needBookKey) {
  319. //获取需要输出的书籍id列表
  320. $needBookResIds[$needBookIds[$needBookKey]] = '';
  321. }
  322. $booksInfoResult = ClientAppService::instance()->userReadBooksInfo($needBookResIds, $this->userInfo);
  323. if ($booksInfoResult->code != ErrorCodeConstants::SUCCESS) {
  324. throw new Exception($booksInfoResult->msg);
  325. }
  326. $result['recommend_book_list'] = $booksInfoResult->data['bookList'];
  327. $this->info($result);
  328. }
  329. }