book-catalog.vue 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. <!--
  2. * @Author: ZhengXiaowei
  3. * @Date: 2019-07-12 09:47:32
  4. * @LastEditors: 晓晓晓晓晓丶vv
  5. * @LastEditTime: 2020-09-14 17:37:28
  6. * @Description: file content
  7. -->
  8. <template>
  9. <div class="book-catalog new-catalog">
  10. <div class="z-header">
  11. <x-header ref="header">
  12. <p class="open-header"
  13. @click="openDialog">
  14. {{ activeName }}<img src="../assets/open.png" />
  15. </p>
  16. </x-header>
  17. </div>
  18. <div class="abs-list">
  19. <div v-infinite-scroll="loadMore"
  20. infinite-scroll-disabled="loading"
  21. infinite-scroll-distance="10">
  22. <template v-for="v in catalogs">
  23. <div class="book-catalog-item"
  24. :key="v.chapter_id"
  25. ref="catalogs"
  26. @click="toReader(v)">
  27. <span class="book-catalog-item__name"
  28. :class="{ 'is-active': sequence === v.chapter_sequence }">{{ v.chapter_name }}
  29. <span v-if="v.is_show_price && v.chapter_is_vip"
  30. class="price-box">
  31. <img src="../assets/price.png"
  32. class="price-icon" />{{ v.price }}
  33. </span>
  34. </span>
  35. <img v-if="v.chapter_is_vip"
  36. src="../assets/书库-vip.png"
  37. class="book-catalog-item__vip" />
  38. </div>
  39. </template>
  40. <mt-spinner v-if="!isLoadLast"
  41. type="fading-circle"
  42. color="#32a1ff"></mt-spinner>
  43. </div>
  44. </div>
  45. <mt-popup v-model="popupVisible"
  46. position="bottom">
  47. <mt-picker :slots="slots"
  48. @change="onValuesChange"
  49. ref="picker"
  50. class="mybook-picker"
  51. value-key="name"
  52. showToolbar>
  53. <div class="picker-title">
  54. <div class="usi-btn-cancel"
  55. @click="cancelTar">
  56. 取消
  57. </div>
  58. <div style="font-weight:bold">请选择章节</div>
  59. <div class="usi-btn-sure"
  60. @click="sureTar">
  61. 确定
  62. </div>
  63. </div>
  64. </mt-picker>
  65. </mt-popup>
  66. </div>
  67. </template>
  68. <script>
  69. import { BookCatalog, Reader, Pay } from "./namespace.js";
  70. import catalogs from "../mock/catalogs.js";
  71. import { getCatalog, getUserInfo } from "../api";
  72. const pageSize = 100;
  73. let catalog = null;
  74. export default {
  75. name: BookCatalog.name,
  76. data() {
  77. return {
  78. Reader: Reader.name,
  79. catalogs: [],
  80. inLoadData: false,
  81. isLoadLast: false,
  82. popupVisible: false,
  83. balance: 0,
  84. activeName: "",
  85. is_vip: false,
  86. sequence: +this.$route.query.sequence,
  87. active: (((+this.$route.query.sequence || 1) / 100) >> 0) + 1,
  88. slots: [
  89. {
  90. flex: 1,
  91. values: [],
  92. className: "slot1",
  93. defaultIndex: 0,
  94. },
  95. ],
  96. uuids:'',
  97. meta: {},
  98. tempPage: 1,
  99. handler: function (e) {
  100. e.preventDefault();
  101. },
  102. };
  103. },
  104. watch: {
  105. popupVisible(val) {
  106. if (val) {
  107. this.closeTouch();
  108. } else {
  109. this.openTouch();
  110. }
  111. },
  112. },
  113. methods: {
  114. openDialog() {
  115. this.popupVisible = true;
  116. },
  117. closeTouch() {
  118. document
  119. .getElementsByTagName("body")[0]
  120. .addEventListener("touchmove", this.handler, { passive: false });
  121. },
  122. openTouch() {
  123. document
  124. .getElementsByTagName("body")[0]
  125. .removeEventListener("touchmove", this.handler, { passive: false });
  126. },
  127. onValuesChange(picker, values) {
  128. if (values[0]) {
  129. this.tempPage = values[0].value;
  130. }
  131. },
  132. cancelTar() {
  133. this.popupVisible = false;
  134. },
  135. sureTar() {
  136. this.isLoadLast = false;
  137. getCatalog(this.$route.query.id, this.tempPage).then((r) => {
  138. let catalog = r;
  139. this.meta = catalog.meta;
  140. this.catalogs = catalog.data;
  141. this.active = catalog.meta.current_page;
  142. this.isLoadLast = r.meta.current_page === r.meta.last_page;
  143. let total = catalog.meta.total;
  144. if (this.active == 1 && this.active != catalog.meta.last_page) {
  145. this.activeName = "1-100章";
  146. } else if (this.active == catalog.meta.last_page) {
  147. this.activeName = `${(this.active - 1) * 100 + 1}-${total}章`;
  148. } else {
  149. this.activeName = `${(this.active - 1) * 100 + 1}-${
  150. this.active * 100
  151. }章`;
  152. }
  153. window.scrollTo(0, 0);
  154. document.documentElement.scrollTop = document.body.scrollTop = 0;
  155. this.popupVisible = false;
  156. });
  157. },
  158. reset() {
  159. //位置重置
  160. if (!isNaN(this.sequence)) {
  161. let currentNext = this.$refs.catalogs[(this.sequence % pageSize) - 2];
  162. let timer = null;
  163. let height = (currentNext.$el || currentNext).offsetTop;
  164. let h =
  165. window.innerHeight ||
  166. document.documentElement.clientHeight ||
  167. document.body.clientHeight;
  168. let h1 =
  169. document.body.clientHeight || document.documentElement.clientHeight;
  170. let h2 = h1 - h;
  171. height > h2 ? (height = h2) : (height = height);
  172. let reset = () => {
  173. window.scrollTo(0, height);
  174. document.documentElement.scrollTop = document.body.scrollTop = height;
  175. clearTimeout(timer);
  176. };
  177. timer = setTimeout(function () {
  178. reset();
  179. }, 50);
  180. }
  181. },
  182. adjustBalance() {
  183. getUserInfo().then((r) => {
  184. this.balance = r.reward_balance;
  185. this.is_vip = r.is_vip;
  186. });
  187. },
  188. toReader(chapter) {
  189. const bid = this.$route.query.id;
  190. const {
  191. chapter_id: cid,
  192. price: chapter_cost,
  193. chapter_is_vip: vip,
  194. } = chapter;
  195. const from_detail_catalog = 2;
  196. if (!this.is_vip && !!vip && chapter_cost > this.balance) {
  197. console.log('vip直接跳去付费,第',cid)
  198. // vip章节 且章节价格>余额
  199. this.$router.push({
  200. name: Pay.name,
  201. query: {
  202. book_id: bid,
  203. chapter_id: cid,
  204. fee: chapter_cost,
  205. code: 10021,
  206. uuids:this.uuids,
  207. from_detail_catalog,
  208. sequence: this.sequence
  209. },
  210. });
  211. } else {
  212. this.$router.push({
  213. name: this.Reader,
  214. query: {
  215. bid,
  216. cid,
  217. uuids:this.uuids,
  218. sendid:this.$route.query.sendid || localStorage.getItem('sendid') || sessionStorage.getItem('sendid'),
  219. from_detail_catalog,
  220. sequence: this.sequence
  221. },
  222. });
  223. }
  224. },
  225. loadMore() {
  226. if (this.inLoadData) return;
  227. this.inLoadData = true;
  228. if (this.isLoadLast) return;
  229. let page = this.meta.current_page;
  230. getCatalog(this.$route.query.id, page + 1).then((r) => {
  231. this.catalogs.push(...r.data);
  232. this.meta = r.meta;
  233. this.isLoadLast = r.meta.current_page === r.meta.last_page;
  234. this.inLoadData = false;
  235. });
  236. },
  237. },
  238. created() {
  239. if (catalog) {
  240. let uuid = localStorage.getItem("uuids");
  241. let {uuids } = this.$route.query;
  242. this.uuids = uuids || uuid;
  243. this.catalogs = catalog.data;
  244. this.meta = catalog.meta;
  245. if (this.catalogs.length > catalog.meta.per_page) {
  246. this.meta.current_page = Math.ceil(
  247. this.catalogs.length / catalog.meta.per_page
  248. );
  249. }
  250. this.active = catalog.meta.current_page;
  251. let end = catalog.meta.last_page;
  252. let total = catalog.meta.total;
  253. for (let i = 1; i <= Math.ceil(total / 100); i++) {
  254. if (i == 1) {
  255. let s;
  256. if (total >= 100) {
  257. s = `${i}-${i * 100}章`;
  258. } else {
  259. s = `${i}-${total}章`;
  260. }
  261. this.slots[0].values.push({ name: s, value: i });
  262. } else if (i == Math.ceil(total / 100)) {
  263. let s = `${(i - 1) * 100 + 1}-${total}章`;
  264. this.slots[0].values.push({ name: s, value: i });
  265. } else {
  266. let s = `${(i - 1) * 100 + 1}-${i * 100}章`;
  267. this.slots[0].values.push({ name: s, value: i });
  268. }
  269. }
  270. this.slots[0].defaultIndex = this.active - 1;
  271. if (this.active == 1 && this.active != catalog.meta.last_page) {
  272. this.activeName = "1-100章";
  273. } else if (this.active == catalog.meta.last_page) {
  274. this.activeName = `${(this.active - 1) * 100 + 1}-${total}章`;
  275. } else {
  276. this.activeName = `${(this.active - 1) * 100 + 1}-${
  277. this.active * 100
  278. }章`;
  279. }
  280. this.$nextTick(this.reset);
  281. } else {
  282. this.activeName = "1-100章";
  283. this.$router.replace("/");
  284. }
  285. this.adjustBalance();
  286. },
  287. beforeRouteEnter(to, from, next) {
  288. let id = to.query.id;
  289. let start = (((+to.query.sequence || 1) / 100) >> 0) + 1;
  290. getCatalog(id, start, "catalog")
  291. .catch((e) => {
  292. let replace_url = e.data.data.url + location.pathname + location.search;
  293. location.replace(replace_url);
  294. })
  295. .then((r) => {
  296. catalog = r;
  297. next();
  298. });
  299. },
  300. };
  301. </script>
  302. <style lang="scss">
  303. .usi-btn-cancel {
  304. color: #666;
  305. }
  306. .usi-btn-sure {
  307. color: #1296db;
  308. }
  309. .picker-title {
  310. display: flex;
  311. justify-content: space-around;
  312. height: 40px;
  313. line-height: 40px;
  314. font-size: 0.28rem;
  315. }
  316. .mybook-picker {
  317. width: 100vw;
  318. height: 4rem;
  319. .picker-item.picker-selected {
  320. color: #1296db;
  321. }
  322. }
  323. .price-box {
  324. margin-left: 20px;
  325. color: #999;
  326. font-size: 0.24rem;
  327. .price-icon {
  328. width: 0.32rem;
  329. height: 0.32rem;
  330. vertical-align: sub;
  331. margin-right: 5px;
  332. }
  333. }
  334. .open-header {
  335. font-size: 0.24rem;
  336. color: #1296db;
  337. img {
  338. background: url(../assets/open.png) no-repeat;
  339. display: inline-block;
  340. vertical-align: sub;
  341. width: 0.34rem;
  342. height: 0.34rem;
  343. }
  344. }
  345. .new-catalog {
  346. .book-catalog-item {
  347. padding: 0 0.3rem;
  348. }
  349. .z-header {
  350. height: 1rem;
  351. }
  352. .x-header {
  353. position: fixed;
  354. height: 1rem;
  355. top: 0;
  356. left: 0;
  357. right: 0;
  358. background: #fff;
  359. }
  360. }
  361. </style>