index.vue 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819
  1. <template>
  2. <div class="bookShelf">
  3. <Header
  4. :headerBg="'#00ADEF'"
  5. :headerBorder="'#5C5C5C'"
  6. :userBg="'rgba(0, 0, 0, 0.24)'"
  7. :LoginNavIndex="0"
  8. />
  9. <ul class="option">
  10. <li
  11. class="option-item"
  12. :class="[typeIndex === indexo ? 'active' : '']"
  13. v-for="(itemo, indexo) in optionList"
  14. :key="indexo"
  15. @click="handleClick(itemo, indexo)"
  16. >
  17. <svg-icon :icon-class="itemo.img" className="icon-img"></svg-icon>
  18. <span>{{ itemo.label }}</span>
  19. <b>{{
  20. itemo.value === -1 || itemo.value === 3
  21. ? itemo.number + orderPeruseNumber
  22. : itemo.number
  23. }}</b>
  24. </li>
  25. </ul>
  26. <div class="main">
  27. <template v-if="userMessage">
  28. <div class="searchChangebox">
  29. <div class="searchChange-box">
  30. <div
  31. class="searchChange"
  32. :class="[item.sortName == sortField ? 'active' : '']"
  33. v-for="(item, indexC) in changeList"
  34. :key="indexC"
  35. >
  36. <span>
  37. {{ item.name }}
  38. </span>
  39. <div :class="['sort']">
  40. <div>
  41. <svg-icon
  42. icon-class="up"
  43. className="icon-up"
  44. :class="[item.sort == 'up' ? 'active' : '']"
  45. @click="SortEvent('up', item.name, item.sortName)"
  46. ></svg-icon>
  47. </div>
  48. <div>
  49. <svg-icon
  50. icon-class="down"
  51. className="icon-down"
  52. :class="[item.sort == 'down' ? 'active' : '']"
  53. @click="SortEvent('down', item.name, item.sortName)"
  54. ></svg-icon>
  55. </div>
  56. </div>
  57. </div>
  58. </div>
  59. <el-input
  60. placeholder="输入名称"
  61. v-model="searchNameValue"
  62. class="input-search"
  63. maxlength="20"
  64. >
  65. <el-button
  66. slot="append"
  67. icon="el-icon-search"
  68. @click="getSearch"
  69. ></el-button>
  70. </el-input>
  71. </div>
  72. <h5 class="show-title" v-if="typeIndex !== 0">
  73. {{ optionList[typeIndex].label
  74. }}<b>{{
  75. optionList[typeIndex].value === 3
  76. ? optionList[typeIndex].number + orderPeruseNumber
  77. : optionList[typeIndex].number
  78. }}</b>
  79. </h5>
  80. <div class="list" v-if="BookList.length > 0">
  81. <!-- v-infinite-scroll="load" -->
  82. <div
  83. v-for="(item, index) in BookList"
  84. :key="index + 'todayNew'"
  85. v-infinite-scroll="load"
  86. infinite-scroll-disabled="disabled"
  87. :class="[item.type === 3 ? 'book-item-peruse' : '']"
  88. >
  89. <template v-if="item.type === 3">
  90. <BookPeruseCard
  91. :item="item"
  92. type="bookShelf"
  93. :headerBg="'#00ADEF'"
  94. :headerBorder="'#5C5C5C'"
  95. :userBg="'rgba(0, 0, 0, 0.24)'"
  96. :LoginNavIndex="0"
  97. :previousPage="'书架'"
  98. />
  99. </template>
  100. <template v-if="item.type === 30">
  101. <BookPeruseListCard
  102. :item="item"
  103. type="bookShelf"
  104. :headerBg="'#00ADEF'"
  105. :headerBorder="'#5C5C5C'"
  106. :userBg="'rgba(0, 0, 0, 0.24)'"
  107. :LoginNavIndex="0"
  108. :previousPage="'书架'"
  109. />
  110. </template>
  111. <template v-else>
  112. <BookCard
  113. :item="item"
  114. type="bookShelf"
  115. :headerBg="'#00ADEF'"
  116. :headerBorder="'#5C5C5C'"
  117. :userBg="'rgba(0, 0, 0, 0.24)'"
  118. :LoginNavIndex="0"
  119. :previousPage="'书架'"
  120. :cardType="item.course_type"
  121. />
  122. </template>
  123. </div>
  124. <p v-if="loading" class="tips">加载中...</p>
  125. <p v-if="noMore" class="tips">没有更多了</p>
  126. </div>
  127. <div class="nodata" v-else>
  128. <img src="../../assets/nodata.png" />
  129. <p>找不到文件</p>
  130. </div>
  131. </template>
  132. <template v-else>
  133. <p class="login-no">
  134. 您还未登录,请先<a
  135. @click="
  136. loginFlag = true;
  137. toUrl = '/bookShelf';
  138. "
  139. >登录</a
  140. >
  141. </p>
  142. </template>
  143. </div>
  144. <el-dialog
  145. :visible.sync="loginFlag"
  146. :show-close="false"
  147. :close-on-click-modal="false"
  148. :modal-append-to-body="false"
  149. width="504px"
  150. class="login-dialog"
  151. v-if="loginFlag"
  152. >
  153. <login @cancelLogin="cancelLogin" :toUrl="toUrl" linkType="url"></login>
  154. </el-dialog>
  155. </div>
  156. </template>
  157. <script>
  158. //这里可以导入其它文件(比如:组件,工具js,第三方插件js,json文件,图片文件等等)
  159. //例如:import 《组件名称》from ‘《组件路径》';
  160. import axios from "axios";
  161. import Header from "../../components/Header.vue";
  162. import BookCard from "@/components/common/BookCard.vue";
  163. import BookPeruseCard from "@/components/common/BookPeruseCard.vue";
  164. import BookPeruseListCard from "@/components/common/BookPeruseListCard.vue";
  165. import { getLogin } from "@/api/ajax";
  166. import { getToken } from "@/utils/auth";
  167. import Login from "@/views/login.vue";
  168. export default {
  169. //import引入的组件需要注入到对象中才能使用
  170. components: { Header, BookCard, BookPeruseCard, BookPeruseListCard, Login },
  171. props: {},
  172. data() {
  173. //这里存放数据
  174. return {
  175. BookList: [
  176. {
  177. skeleton: true,
  178. },
  179. {
  180. skeleton: true,
  181. },
  182. {
  183. skeleton: true,
  184. },
  185. {
  186. skeleton: true,
  187. },
  188. {
  189. skeleton: true,
  190. },
  191. ],
  192. optionList: [
  193. {
  194. label: "全部",
  195. img: "quanbu",
  196. number: 0,
  197. value: -1,
  198. },
  199. {
  200. label: "画刊",
  201. img: "huakan",
  202. number: 0,
  203. value: 4,
  204. },
  205. {
  206. label: "报纸",
  207. img: "baozhi",
  208. number: 0,
  209. value: 2,
  210. },
  211. {
  212. label: "练习册",
  213. img: "xiti",
  214. number: 0,
  215. },
  216. {
  217. label: "课程",
  218. img: "kecheng",
  219. number: 0,
  220. value: 10,
  221. },
  222. {
  223. label: "精读",
  224. img: "jingdu",
  225. number: 0,
  226. value: 3,
  227. },
  228. {
  229. label: "专辑",
  230. img: "zhuanji",
  231. number: 0,
  232. value: 20,
  233. },
  234. // ,
  235. // {
  236. // label: '合刊',
  237. // img: 'hekan',
  238. // number: '6'
  239. // }
  240. ],
  241. typeValue: -1,
  242. changeList: [
  243. {
  244. name: "按购买时间",
  245. sort: "down",
  246. sortName: "buy_time",
  247. },
  248. {
  249. name: "发行日期",
  250. sort: "",
  251. sortName: "shelve_date",
  252. },
  253. {
  254. name: "最近使用",
  255. sort: "",
  256. sortName: "last_use_time",
  257. },
  258. ],
  259. sortField: "",
  260. searchNameValue: "", // 搜索名称值
  261. loading: false,
  262. noMore: false,
  263. pageNumber: 1,
  264. pageSize: 50,
  265. typeIndex: 0,
  266. orderPeruseNumber: 0, // 精读订阅个数
  267. userMessage: getToken() ? JSON.parse(getToken()) : null,
  268. loginFlag: false,
  269. toUrl: "",
  270. stopLoad: false,
  271. cancelToken: null,
  272. source: axios.CancelToken.source(),
  273. loadFlag: true,
  274. };
  275. },
  276. //计算属性 类似于data概念
  277. computed: {
  278. disabled() {
  279. return this.loading || this.noMore || this.stopLoad;
  280. },
  281. },
  282. //监控data中数据变化
  283. watch: {},
  284. //方法集合
  285. methods: {
  286. handleClick(item, index) {
  287. this.stopLoad = true;
  288. this.typeIndex = index;
  289. this.pageNumber = 1;
  290. if (item.hasOwnProperty("value")) {
  291. this.typeValue = item.value;
  292. if (item.number > 0 || item.value === 3 || item.value === -1) {
  293. this.BookList = [
  294. {
  295. skeleton: true,
  296. },
  297. {
  298. skeleton: true,
  299. },
  300. {
  301. skeleton: true,
  302. },
  303. {
  304. skeleton: true,
  305. },
  306. {
  307. skeleton: true,
  308. },
  309. ];
  310. this.BookList = [];
  311. this.stopLoad = false;
  312. this.getList();
  313. } else {
  314. this.typeValue = null;
  315. this.BookList = [];
  316. }
  317. } else {
  318. this.typeValue = null;
  319. this.BookList = [];
  320. }
  321. this.source.cancel("Operation canceled by the user.");
  322. $(".list").animate(
  323. {
  324. scrollTop: 0,
  325. },
  326. 200
  327. );
  328. },
  329. // 搜索查询
  330. getSearch() {
  331. this.pageNumber = 1;
  332. this.BookList = [
  333. {
  334. skeleton: true,
  335. },
  336. {
  337. skeleton: true,
  338. },
  339. {
  340. skeleton: true,
  341. },
  342. {
  343. skeleton: true,
  344. },
  345. {
  346. skeleton: true,
  347. },
  348. ];
  349. this.BookList = [];
  350. $(".list").animate(
  351. {
  352. scrollTop: 0,
  353. },
  354. 200
  355. );
  356. this.getList();
  357. },
  358. SortEvent(type, name, sortName) {
  359. this.stopLoad = true;
  360. let sort = "";
  361. this.changeList.forEach((item) => {
  362. if (item.name == name) {
  363. // if (!item.sort || item.sort == "up") {
  364. // item.sort = "down";
  365. // sort = "down";
  366. // } else if (item.sort == "down") {
  367. // item.sort = "up";
  368. // sort = "up";
  369. // }
  370. item.sort = type;
  371. sort = type;
  372. } else {
  373. item.sort = "";
  374. }
  375. });
  376. if (sort == "down") {
  377. this.sortType = 1;
  378. } else {
  379. this.sortType = 0;
  380. }
  381. this.sortField = sortName;
  382. $(".list").animate(
  383. {
  384. scrollTop: 0,
  385. },
  386. 200
  387. );
  388. this.stopLoad = false;
  389. this.pageNumber = 1;
  390. this.getList();
  391. },
  392. // 查询列表
  393. async getList() {
  394. this.cancelToken = this.source.token;
  395. this.loading = true;
  396. let MethodName = "/ShopServer/Client/BookshelfQuery/PageQueryMyGoodsList";
  397. let order_column_list = [];
  398. if (this.sortField !== "") {
  399. if (this.sortType === 1) {
  400. order_column_list = [this.sortField + ":desc"];
  401. } else if (this.sortType === 0) {
  402. // 升序不传值
  403. order_column_list = [this.sortField];
  404. }
  405. } else {
  406. order_column_list = ["buy_time:desc"];
  407. }
  408. let data = {
  409. goods_name: this.searchNameValue.trim(),
  410. goods_type: this.typeValue,
  411. page_capacity: this.pageSize,
  412. cur_page: this.pageNumber,
  413. order_column_list: order_column_list,
  414. };
  415. await getLogin(MethodName, data, { cancelToken: this.source.token })
  416. .then((res) => {
  417. this.loading = false;
  418. if (res.status === 1) {
  419. if (res.goods_list.length === 0 && res.cur_page === 0) {
  420. this.loadFlag = false;
  421. this.handleOnlyPer();
  422. return;
  423. }
  424. this.loadFlag = true;
  425. if (
  426. this.typeValue === -1 ||
  427. (this.typeValue === 10 &&
  428. res.goods_list[0].type === 0 &&
  429. res.goods_list.length > 0) ||
  430. (this.typeValue === res.goods_list[0].type &&
  431. res.goods_list.length > 0)
  432. ) {
  433. if (res.cur_page === 1) {
  434. // this.BookList = [];
  435. if (this.typeValue === -1 || this.typeValue === 3) {
  436. getLogin(
  437. "/ShopServer/Client/BookshelfQuery/GetMyValidPeriodList_Iread",
  438. {}
  439. ).then((ress) => {
  440. if (ress.status === 1) {
  441. if (res.cur_page === 1) {
  442. this.orderPeruseNumber = ress.valid_period_list.length;
  443. ress.valid_period_list.forEach((items) => {
  444. items.type = 30;
  445. });
  446. this.BookList = ress.valid_period_list.concat(
  447. res.goods_list
  448. );
  449. }
  450. } else {
  451. this.BookList = res.goods_list;
  452. }
  453. });
  454. } else {
  455. this.BookList = res.goods_list;
  456. }
  457. this.noMore = false;
  458. } else if (res.cur_page !== 1) {
  459. this.BookList = this.BookList.concat(res.goods_list);
  460. }
  461. if (res.total_page * this.pageSize <= res.cur_page_end_index) {
  462. this.noMore = true;
  463. }
  464. } else {
  465. // this.BookList = [];
  466. }
  467. }
  468. })
  469. .catch((error) => {
  470. this.loading = false;
  471. if (axios.isCancel(error)) {
  472. console.log("Request canceled", error.message);
  473. } else {
  474. console.error("Error occurred:", error);
  475. }
  476. });
  477. },
  478. handleOnlyPer() {
  479. if (this.typeValue === -1 || this.typeValue === 3) {
  480. getLogin(
  481. "/ShopServer/Client/BookshelfQuery/GetMyValidPeriodList_Iread",
  482. {}
  483. ).then((ress) => {
  484. if (ress.status === 1) {
  485. this.orderPeruseNumber = ress.valid_period_list.length;
  486. ress.valid_period_list.forEach((items) => {
  487. items.type = 30;
  488. });
  489. this.BookList = ress.valid_period_list;
  490. } else {
  491. this.BookList = [];
  492. }
  493. });
  494. }
  495. },
  496. load() {
  497. if (this.userMessage && this.loadFlag) {
  498. if (
  499. this.pageNumber > 2 &&
  500. (this.typeValue === -1 ||
  501. (this.typeValue === 10 &&
  502. this.BookList[0].type === 0 &&
  503. this.BookList.length > 0) ||
  504. (this.typeValue === this.BookList[0].type &&
  505. this.BookList.length > 0))
  506. ) {
  507. this.pageNumber++;
  508. this.getList();
  509. } else {
  510. this.pageNumber++;
  511. this.getList();
  512. }
  513. }
  514. },
  515. // 获取商品个数
  516. getNumber() {
  517. let MethodName = "/ShopServer/Client/BookshelfQuery/GetMyGoodsCount";
  518. getLogin(MethodName, {})
  519. .then((res) => {
  520. if (res.status === 1) {
  521. this.optionList = [
  522. {
  523. label: "全部",
  524. img: "quanbu",
  525. number: res.count_all,
  526. value: -1,
  527. },
  528. {
  529. label: "画刊",
  530. img: "huakan",
  531. number: res.count_pictorial,
  532. value: 4,
  533. },
  534. {
  535. label: "报纸",
  536. img: "baozhi",
  537. number: res.count_issue,
  538. value: 2,
  539. },
  540. {
  541. label: "练习册",
  542. img: "xiti",
  543. number: 0,
  544. },
  545. {
  546. label: "课程",
  547. img: "kecheng",
  548. number: res.count_course,
  549. value: 10,
  550. },
  551. {
  552. label: "精读课堂",
  553. img: "jingdu",
  554. number: res.count_iread,
  555. value: 3,
  556. },
  557. {
  558. label: "专辑",
  559. img: "zhuanji",
  560. number: res.count_album,
  561. value: 20,
  562. },
  563. // ,
  564. // {
  565. // label: '合刊',
  566. // img: 'hekan',
  567. // number: '6'
  568. // }
  569. ];
  570. }
  571. })
  572. .catch(() => {
  573. this.loading = false;
  574. });
  575. },
  576. // 关闭登录弹窗
  577. cancelLogin() {
  578. this.loginFlag = false;
  579. },
  580. },
  581. //生命周期 - 创建完成(可以访问当前this实例)
  582. created() {
  583. console.log("2025-08-20");
  584. if (this.userMessage) {
  585. this.getNumber();
  586. this.getList();
  587. }
  588. },
  589. //生命周期 - 挂载完成(可以访问DOM元素)
  590. mounted() {
  591. if (this.userMessage) {
  592. let _this = this;
  593. let input = document.querySelector("input");
  594. input.addEventListener("keyup", function (event) {
  595. // 判断是否按下回车键
  596. if (event.keyCode === 13) {
  597. // 回车键被按下,执行你想要的操作
  598. _this.getList(1);
  599. }
  600. });
  601. }
  602. },
  603. //生命周期-创建之前
  604. beforeCreated() {},
  605. //生命周期-挂载之前
  606. beforeMount() {},
  607. //生命周期-更新之前
  608. beforUpdate() {},
  609. //生命周期-更新之后
  610. updated() {},
  611. //生命周期-销毁之前
  612. beforeDestory() {},
  613. //生命周期-销毁完成
  614. destoryed() {},
  615. //如果页面有keep-alive缓存功能,这个函数会触发
  616. activated() {},
  617. };
  618. </script>
  619. <style lang="scss" scoped>
  620. /* @import url(); 引入css类 */
  621. .bookShelf {
  622. background: #f7f8fa;
  623. height: calc(100vh - 64px);
  624. .option {
  625. list-style: none;
  626. display: flex;
  627. justify-content: center;
  628. margin: 0;
  629. padding: 0;
  630. background: #00adef;
  631. li {
  632. display: flex;
  633. align-items: center;
  634. border-radius: 30px;
  635. height: 36px;
  636. padding: 7px 20px;
  637. margin: 8px 4px;
  638. cursor: pointer;
  639. &:hover {
  640. background: rgba(255, 255, 255, 0.08);
  641. }
  642. &.active {
  643. background: rgba(255, 255, 255, 0.08);
  644. .icon-img,
  645. span,
  646. b {
  647. color: rgba(255, 255, 255, 0.9);
  648. }
  649. }
  650. .icon-img {
  651. width: 14px;
  652. height: 14px;
  653. margin: 1px 8px 0 0;
  654. color: rgba(255, 255, 255, 0.5);
  655. }
  656. span {
  657. color: rgba(255, 255, 255, 0.5);
  658. font-size: 14px;
  659. line-height: 22px;
  660. }
  661. b {
  662. font-weight: 400;
  663. font-size: 14px;
  664. line-height: 22px;
  665. color: rgba(255, 255, 255, 0.5);
  666. margin-left: 5px;
  667. }
  668. }
  669. }
  670. .main {
  671. width: 1200px;
  672. margin: 0 auto;
  673. padding: 24px 0 0 0;
  674. .searchChangebox {
  675. display: flex;
  676. justify-content: space-between;
  677. .searchChange-box {
  678. display: flex;
  679. }
  680. .searchChange {
  681. display: flex;
  682. align-items: center;
  683. justify-content: space-between;
  684. padding: 4px 12px;
  685. height: 32px;
  686. margin-right: 16px;
  687. border: 1px solid #e5e6eb;
  688. border-radius: 20px;
  689. &.active {
  690. background: #175dff;
  691. > span {
  692. color: #ffffff;
  693. }
  694. .sort {
  695. > div {
  696. svg {
  697. color: #5e89ef;
  698. &.active {
  699. color: #ffffff;
  700. }
  701. }
  702. }
  703. }
  704. }
  705. > span {
  706. font-weight: 400;
  707. font-size: 16px;
  708. line-height: 22px;
  709. color: #000;
  710. margin-right: 4px;
  711. }
  712. .sort {
  713. cursor: pointer;
  714. height: 20px;
  715. > div {
  716. font-size: 0;
  717. svg {
  718. width: 11px;
  719. height: 11px;
  720. color: #c2c2c2;
  721. padding: 3px 2px 2px 2px;
  722. &.icon-down {
  723. height: 9px;
  724. padding: 0 2px 2px 2px;
  725. }
  726. }
  727. }
  728. }
  729. }
  730. .input-search {
  731. width: 220px;
  732. }
  733. }
  734. .show-title {
  735. color: #1f2c5c;
  736. margin: 24px 0 0 0;
  737. font-weight: 500;
  738. font-size: 24px;
  739. line-height: 32px;
  740. b {
  741. margin-left: 16px;
  742. color: #ed5f00;
  743. }
  744. }
  745. .list {
  746. margin: 28px -25px 0 -25px;
  747. display: flex;
  748. flex-wrap: wrap;
  749. height: calc(100vh - 256px);
  750. overflow-y: scroll;
  751. &::-webkit-scrollbar {
  752. display: none;
  753. }
  754. > div {
  755. width: 200px;
  756. height: 352px;
  757. border-radius: 8px;
  758. overflow: hidden;
  759. background: #ffffff;
  760. margin: 0 25px 24px 25px;
  761. &.book-item-peruse {
  762. width: 200px;
  763. height: 298px;
  764. margin-top: 54px;
  765. }
  766. }
  767. .tips {
  768. width: 100%;
  769. text-align: center;
  770. font-size: 12px;
  771. color: #929ca8;
  772. }
  773. }
  774. }
  775. }
  776. </style>
  777. <style lang="scss">
  778. .bookShelf {
  779. .searchChangebox {
  780. .input-search {
  781. .el-input__inner {
  782. height: 32px;
  783. color: #1d2129;
  784. background: #f2f3f5;
  785. border: none;
  786. line-height: 32px;
  787. }
  788. .el-input-group__append {
  789. border: none;
  790. width: 32px;
  791. height: 32px;
  792. background: #165dff;
  793. text-align: center;
  794. cursor: pointer;
  795. &:hover {
  796. background: #4080ff;
  797. }
  798. &:focus {
  799. background: #0e42d2;
  800. }
  801. }
  802. .el-button {
  803. padding: 10px 12px;
  804. color: #ffffff;
  805. }
  806. }
  807. }
  808. }
  809. .login-no {
  810. text-align: center;
  811. line-height: 500px;
  812. a {
  813. color: #00adef;
  814. }
  815. }
  816. </style>