图书馆小程序
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.

334 lines
9.2 KiB

1 month ago
  1. <template>
  2. <view class="lending-container">
  3. <view class="tab-sticky">
  4. <my-tabs
  5. :tabData="tabData"
  6. :defaultIndex="currentIndex"
  7. :config="{ textColor: '#333' }"
  8. @tabClick="tabClick"
  9. />
  10. </view>
  11. <swiper
  12. class="swiper"
  13. :current="currentIndex"
  14. :style="{ height: currentSwiperHeight + 'px' }"
  15. @animationfinish="onSwiperEnd"
  16. @change="onSwiperChange"
  17. >
  18. <swiper-item v-for="(tabItem, idx) in tabData" :key="idx">
  19. <view class="list-wrapper">
  20. <!-- 首次加载 -->
  21. <uni-load-more status="loading" v-if="loadingMap[tabItem.status]" />
  22. <!-- 空数据 -->
  23. <view class="empty" v-else-if="!listData[tabItem.status] || listData[tabItem.status].length === 0">
  24. 暂无{{ tabItem.label }}记录
  25. </view>
  26. <!-- 列表 -->
  27. <block v-else>
  28. <lending-list-item
  29. :class="'list-item-' + tabItem.status"
  30. v-for="(item, index) in listData[tabItem.status]"
  31. :key="index"
  32. :data="item"
  33. :ranking="index + 1"
  34. />
  35. </block>
  36. <!-- 上拉加载更多 -->
  37. <uni-load-more
  38. v-if="listData[tabItem.status] && listData[tabItem.status].length > 0 && !loadingMap[tabItem.status]"
  39. :status="loadMoreStatusMap[tabItem.status]"
  40. />
  41. </view>
  42. </swiper-item>
  43. </swiper>
  44. </view>
  45. </template>
  46. <script>
  47. import { FetchInitScreenSetting } from '@/api/user';
  48. import { FetchHistoryloan, FetchRdloanlist } from '@/api/book';
  49. import myTabs from "@/components/my-tabs/my-tabs.vue";
  50. import lendingListItem from "@/components/lending-list-item/lending-list-item.vue";
  51. export default {
  52. components: { myTabs, lendingListItem },
  53. data() {
  54. return {
  55. screenConfig: {},
  56. tabData: [
  57. { label: "全部", status: "all", apiStatus: -1 },
  58. { label: "在借中", status: "lending", apiStatus: 0 },
  59. // { label: "将过期", status: "expiring", apiStatus: 1 },
  60. // { label: "已过期", status: "expired", apiStatus: 2 },
  61. ],
  62. currentIndex: 0,
  63. listData: {},
  64. loadingMap: {},
  65. loadMoreStatusMap: {},
  66. pageMap: {},
  67. sizeMap: {},
  68. hasMoreMap: {},
  69. swiperHeightData: {},
  70. currentSwiperHeight: 400,
  71. currentPageScrollTop: 0,
  72. isRefreshing: false
  73. };
  74. },
  75. onLoad() {
  76. this.getScreenSetting();
  77. this.initDataStructure();
  78. },
  79. onShow() {
  80. const tabIndex = uni.getStorageSync('switch_tab_index');
  81. if (tabIndex !== undefined && tabIndex !== '') {
  82. this.currentIndex = Number(tabIndex);
  83. uni.removeStorageSync('switch_tab_index');
  84. }
  85. },
  86. onPullDownRefresh() {
  87. this.isRefreshing = true;
  88. const currentTab = this.getCurrentTab();
  89. this.refreshList(currentTab.status);
  90. },
  91. onReachBottom() {
  92. const currentTab = this.getCurrentTab();
  93. this.loadMoreList(currentTab.status);
  94. },
  95. onPageScroll(res) {
  96. this.currentPageScrollTop = res.scrollTop;
  97. },
  98. methods: {
  99. async getScreenSetting() {
  100. try {
  101. const res = await FetchInitScreenSetting({ libcode: '1201' });
  102. const data = res.data;
  103. this.screenConfig = {
  104. thirdUrl: data.open_lib_http?.context || '',
  105. thirdAppid: data.open_lib_appId?.context || '',
  106. thirdSecret: data.open_lib_secret?.context || '',
  107. sm4Key: data.sm4_key?.context || ''
  108. };
  109. } catch (err) {
  110. console.error('获取配置失败:', err);
  111. }
  112. },
  113. // 获取 在借中 列表(字段已对齐)
  114. async getRealBorrowList(statusKey) {
  115. this.loadingMap[statusKey] = true;
  116. try {
  117. const rdid = uni.getStorageSync('currentReaderCard');
  118. const params = { ...this.screenConfig, rdid };
  119. const res = await FetchRdloanlist(params);
  120. const result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
  121. let loanList = result.loanlist || [];
  122. // 对齐字段:loandate → loantime,returndate → returntime
  123. loanList = loanList.map(item => {
  124. const loantime = item.loandate || '';
  125. const returntime = item.returndate || '';
  126. const now = new Date();
  127. const returnDate = new Date(returntime);
  128. const diffDay = Math.ceil((returnDate - now) / (1000 * 3600 * 24));
  129. let returnBook = 0;
  130. if (diffDay < 0) {
  131. returnBook = 3;
  132. } else if (diffDay <= 3) {
  133. returnBook = 1;
  134. } else {
  135. returnBook = 0;
  136. }
  137. return {
  138. ...item,
  139. loantime,
  140. returntime,
  141. startTime: loantime,
  142. returnTime: returntime,
  143. returnBook
  144. };
  145. });
  146. console.log('当前借阅', loanList);
  147. this.listData['lending'] = loanList;
  148. this.listData['expiring'] = loanList.filter(i => i.returnBook === 1);
  149. this.listData['expired'] = loanList.filter(i => i.returnBook === 3);
  150. this.hasMoreMap[statusKey] = false;
  151. this.loadMoreStatusMap[statusKey] = "no-more";
  152. } catch (err) {
  153. console.error('获取在借列表失败', err);
  154. this.listData[statusKey] = [];
  155. } finally {
  156. this.loadingMap[statusKey] = false;
  157. this.isRefreshing = false;
  158. uni.stopPullDownRefresh();
  159. setTimeout(() => this.calcSwiperHeight(statusKey), 0);
  160. }
  161. },
  162. // 获取 全部/历史 列表
  163. async getHistoryList(statusKey) {
  164. this.loadingMap[statusKey] = true;
  165. try {
  166. const rdid = uni.getStorageSync('currentReaderCard');
  167. const params = { ...this.screenConfig, rdid, logtype:'30002' };
  168. const res = await FetchHistoryloan(params);
  169. const result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
  170. let loanList = result.hloanlist || [];
  171. loanList = loanList.map(item => {
  172. return {
  173. ...item,
  174. returnTime: item.returntime || '',
  175. startTime: item.loantime || item.optime || '',
  176. returnBook: 2
  177. };
  178. });
  179. console.log('历史借阅', loanList);
  180. this.listData[statusKey] = loanList;
  181. this.hasMoreMap[statusKey] = false;
  182. this.loadMoreStatusMap[statusKey] = "no-more";
  183. } catch (err) {
  184. console.error('获取历史列表失败', err);
  185. this.listData[statusKey] = [];
  186. } finally {
  187. this.loadingMap[statusKey] = false;
  188. this.isRefreshing = false;
  189. uni.stopPullDownRefresh();
  190. setTimeout(() => this.calcSwiperHeight(statusKey), 0);
  191. }
  192. },
  193. initDataStructure() {
  194. this.tabData.forEach(tab => {
  195. const key = tab.status;
  196. this.$set(this.listData, key, []);
  197. this.$set(this.loadingMap, key, true);
  198. this.$set(this.loadMoreStatusMap, key, "");
  199. this.$set(this.pageMap, key, 1);
  200. this.$set(this.sizeMap, key, 10);
  201. this.$set(this.hasMoreMap, key, true);
  202. });
  203. },
  204. getCurrentTab() {
  205. return this.tabData[this.currentIndex];
  206. },
  207. async getListData(statusKey) {
  208. if (statusKey === 'all') {
  209. await this.getHistoryList(statusKey);
  210. }
  211. if (statusKey === 'lending') {
  212. await this.getRealBorrowList(statusKey);
  213. }
  214. if (statusKey === 'expiring' || statusKey === 'expired') {
  215. await this.getRealBorrowList('lending');
  216. this.loadingMap[statusKey] = false;
  217. }
  218. },
  219. loadMoreList(statusKey) {
  220. this.loadMoreStatusMap[statusKey] = "no-more";
  221. },
  222. refreshList(statusKey) {
  223. this.getListData(statusKey);
  224. },
  225. calcSwiperHeight(statusKey) {
  226. const selector = `.list-item-${statusKey}`;
  227. const query = uni.createSelectorQuery().in(this);
  228. query.selectAll(selector).boundingClientRect((res) => {
  229. let total = 200;
  230. if (res?.length) {
  231. total = res.reduce((t, h) => t + h.height + 8, 0);
  232. }
  233. this.swiperHeightData[statusKey] = total;
  234. this.currentSwiperHeight = total;
  235. }).exec();
  236. },
  237. tabClick(index) {
  238. this.currentIndex = index;
  239. const tab = this.getCurrentTab();
  240. if (this.currentPageScrollTop > 100) {
  241. uni.pageScrollTo({ scrollTop: 0, duration: 100 });
  242. }
  243. this.getListData(tab.status);
  244. },
  245. onSwiperChange(e) {
  246. if (e.detail.source === "touch") {
  247. this.currentIndex = e.detail.current;
  248. }
  249. },
  250. onSwiperEnd() {
  251. const tab = this.getCurrentTab();
  252. this.getListData(tab.status);
  253. },
  254. goToDetail(item) {
  255. uni.navigateTo({
  256. url: `/subpkg/pages/book-detail/book-detail?isbn=${item.isbn}`
  257. });
  258. }
  259. }
  260. };
  261. </script>
  262. <style lang="scss" scoped>
  263. .lending-container {
  264. background-color: #f5f5f5;
  265. min-height: 100vh;
  266. .tab-sticky {
  267. position: sticky;
  268. top: 0;
  269. z-index: 99;
  270. background: #fff;
  271. }
  272. .swiper {
  273. width: 100%;
  274. min-height: 300px;
  275. }
  276. .swiper-item {
  277. width: 100%;
  278. height: 100%;
  279. }
  280. .list-wrapper {
  281. padding: 10px;
  282. box-sizing: border-box;
  283. }
  284. .empty {
  285. text-align: center;
  286. padding: 100px 0;
  287. color: #999;
  288. font-size: 14px;
  289. }
  290. }
  291. ::v-deep .uni-load-more{
  292. height: auto !important;
  293. }
  294. </style>