图书馆小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
3.5 KiB

2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
2 months ago
1 month ago
2 months ago
  1. <template>
  2. <view class="container">
  3. <!-- 图书列表 -->
  4. <view class="list-box">
  5. <book-list-item
  6. v-for="(item, index) in bookList"
  7. :key="index"
  8. :data="item"
  9. :ranking="index + 1"
  10. @click="goToDetail(item)"
  11. />
  12. </view>
  13. <!-- 加载提示 -->
  14. <view class="load-tip" v-if="loading">加载中...</view>
  15. <view class="load-tip" v-if="noMore">没有更多了</view>
  16. </view>
  17. </template>
  18. <script>
  19. import bookListItem from "@/components/book-list-item/book-list-item.vue";
  20. import { FetchInitScreenBookRecommend } from '@/api/book';
  21. import config from '@/utils/config';
  22. export default {
  23. components: {
  24. bookListItem
  25. },
  26. data() {
  27. return {
  28. bookList: [],
  29. loading: false,
  30. noMore: false,
  31. baseUrl: config.baseUrl
  32. };
  33. },
  34. onLoad() {
  35. this.getBookRecommendList();
  36. },
  37. onPullDownRefresh() {
  38. this.refresh();
  39. },
  40. methods: {
  41. urlToBase64(url) {
  42. return new Promise((resolve, reject) => {
  43. uni.request({
  44. url,
  45. method: 'GET',
  46. responseType: 'arraybuffer',
  47. success: (res) => {
  48. try {
  49. const buffer = new Uint8Array(res.data);
  50. let binary = '';
  51. for (let i = 0; i < buffer.length; i++) {
  52. binary += String.fromCharCode(buffer[i]);
  53. }
  54. const base64 = uni.arrayBufferToBase64(res.data);
  55. const dataUri = 'data:image/jpeg;base64,' + base64;
  56. resolve(dataUri);
  57. } catch (e) {
  58. reject(e);
  59. }
  60. },
  61. fail: reject
  62. });
  63. });
  64. },
  65. // 刷新
  66. refresh() {
  67. this.bookList = [];
  68. this.noMore = false;
  69. this.getBookRecommendList();
  70. },
  71. async getBookRecommendList() {
  72. this.loading = true;
  73. try {
  74. const res = await FetchInitScreenBookRecommend({ libcode: config.LIB_CODE });
  75. let books = res.data || [];
  76. // 1. 先显示列表(图片为空,显示默认图)
  77. books = books.map(item => {
  78. item.base64Cover = '';
  79. return item;
  80. });
  81. this.bookList = books;
  82. this.noMore = true;
  83. this.loading = false;
  84. uni.stopPullDownRefresh();
  85. // 2. 延迟一点点,等页面渲染完
  86. setTimeout(() => {
  87. this.loadImagesOneByOne(); // 挨个加载图片
  88. }, 200);
  89. } catch (err) {
  90. console.error(err);
  91. this.loading = false;
  92. uni.stopPullDownRefresh();
  93. }
  94. },
  95. async loadImagesOneByOne() {
  96. for (let i = 0; i < this.bookList.length; i++) {
  97. let item = this.bookList[i];
  98. if (!item.imgPath) continue;
  99. // 加载当前这张
  100. const url = this.baseUrl + '/api/fileRelevant/getImg?imgType=2&imgId=' + item.imgPath;
  101. const base64 = await this.urlToBase64(url);
  102. if (base64) {
  103. item.base64Cover = base64;
  104. this.$set(this.bookList, i, item); // 强制更新视图
  105. }
  106. }
  107. },
  108. goToDetail(item) {
  109. uni.navigateTo({
  110. url: "/subpkg/pages/book-detail/book-detail?bookData=" + encodeURIComponent(JSON.stringify(item)) + "&fromRecommend=true"
  111. })
  112. },
  113. }
  114. };
  115. </script>
  116. <style lang="scss" scoped>
  117. .container {
  118. padding: 10px;
  119. background-color: #f5f5f5;
  120. min-height: 100vh;
  121. }
  122. .list-box {
  123. display: flex;
  124. flex-direction: column;
  125. gap: 8px;
  126. }
  127. .load-tip {
  128. text-align: center;
  129. padding: 15px;
  130. font-size: 14px;
  131. color: #999;
  132. }
  133. </style>