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

245 lines
6.8 KiB

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
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 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
2 months ago
1 month ago
2 months ago
1 month ago
2 months ago
1 month 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
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
2 months ago
  1. <template>
  2. <view class="item-container">
  3. <view v-if="bookList.length !== 0" class="count-text">
  4. <text>图书数量 ({{ bookList.length }})</text>
  5. </view>
  6. <view class="car-list" v-for="item in bookList" :key="item.barcode">
  7. <checkbox :checked="item.checked" @click="toggleItem(item)" />
  8. <view class="book-item-box">
  9. <view class="item-box-left">
  10. <image class="img-item" :src="defaultCover" mode="aspectFill" />
  11. </view>
  12. <view class="item-box-right">
  13. <view class="item-title line-clamp-2">{{ item.title || '暂无标题' }}</view>
  14. <view class="tag-box">
  15. <text class="item-author">{{ item.author || '佚名' }}</text>
  16. </view>
  17. <view class="item-desc">应还时间{{ item.returndate || '暂无' }}</view>
  18. </view>
  19. </view>
  20. </view>
  21. <view class="empty" v-if="bookList.length === 0">
  22. <uni-icons style="margin-left: 20px;" custom-prefix="iconfont" type="icon-kongshuju" size="80"></uni-icons>
  23. <text style="margin-top: 20px;">暂无相关数据</text>
  24. </view>
  25. <view class="bottom-placeholder"></view>
  26. <view class="car-bottom">
  27. <!-- 全选 -->
  28. <view class="all-check" @click="toggleAllCheck">
  29. <checkbox :checked="isAllChecked" />
  30. <text style="margin-left:6px">全选</text>
  31. </view>
  32. <button class="join-btn" @click="handleRenew" :disabled="!hasChecked">
  33. 一键续借
  34. </button>
  35. </view>
  36. </view>
  37. </template>
  38. <script>
  39. import { FetchInitScreenSetting } from '@/api/user';
  40. import { FetchRdloanlist, FetchRenewbook, FetchDeletebook } from '@/api/book';
  41. import { getCurrentReaderCard } from '@/utils/storage';
  42. export default {
  43. data() {
  44. return {
  45. bookList: [],
  46. defaultCover: '/static/images/default-book.png',
  47. screenConfig: {},
  48. };
  49. },
  50. onShow() {
  51. this.getConfigAndList();
  52. },
  53. computed: {
  54. // 全选状态
  55. isAllChecked() {
  56. return this.bookList.length > 0 && this.bookList.every(item => item.checked);
  57. },
  58. // 是否有选中
  59. hasChecked() {
  60. return this.bookList.some(item => item.checked);
  61. }
  62. },
  63. methods: {
  64. async getConfigAndList() {
  65. try {
  66. const res = await FetchInitScreenSetting({ libcode: '1201' });
  67. this.screenConfig = {
  68. thirdUrl: res.data.open_lib_http?.context || '',
  69. thirdAppid: res.data.open_lib_appId?.context || '',
  70. thirdSecret: res.data.open_lib_secret?.context || '',
  71. sm4Key: res.data.sm4_key?.context || '',
  72. opuser: res.data.op_user?.context || 'JH001',
  73. };
  74. this.getLendingList();
  75. } catch (err) {}
  76. },
  77. async getLendingList() {
  78. try {
  79. // 使用带缓存降级的函数获取读者证
  80. const currentReaderCard = await getCurrentReaderCard();
  81. console.log('当前证:', currentReaderCard);
  82. const params = {
  83. ...this.screenConfig,
  84. rdid: currentReaderCard.bindValue,
  85. };
  86. const res = await FetchRdloanlist(params);
  87. const result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
  88. // 每条数据加 checked: false 购物车选中状态
  89. this.bookList = (result.loanlist || []).map(item => ({
  90. ...item,
  91. checked: false
  92. }));
  93. } catch (err) {
  94. uni.showToast({ title: '加载失败', icon: 'none' });
  95. }
  96. },
  97. // 单个勾选(购物车逻辑)
  98. toggleItem(item) {
  99. item.checked = !item.checked;
  100. },
  101. // 全选/取消全选
  102. toggleAllCheck() {
  103. const isAll = this.isAllChecked;
  104. this.bookList.forEach(item => {
  105. item.checked = !isAll;
  106. });
  107. },
  108. // 一键续借
  109. async handleRenew() {
  110. const checkedBooks = this.bookList.filter(item => item.checked);
  111. if (checkedBooks.length === 0) {
  112. uni.showToast({ title: '请选择图书', icon: 'none' });
  113. return;
  114. }
  115. const barcodes = checkedBooks.map(item => item.barcode).join('|');
  116. uni.showLoading({ title: '续借中...' });
  117. try {
  118. // 使用带缓存降级的函数获取读者证
  119. const currentReaderCard = await getCurrentReaderCard();
  120. const params = {
  121. ...this.screenConfig,
  122. rdid: currentReaderCard.bindValue,
  123. barcode: barcodes,
  124. logtype: '30007'
  125. };
  126. const res = await FetchRenewbook(params);
  127. // 解析接口返回的 data 字符串
  128. const result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
  129. uni.hideLoading();
  130. if (result.success === true) {
  131. // 续借成功
  132. uni.showToast({
  133. title: `续借成功!`,
  134. icon: 'success'
  135. });
  136. // 刷新列表
  137. this.getLendingList();
  138. } else {
  139. // 续借失败 → 取后台提示信息
  140. let msg = '续借失败';
  141. if (result.messagelist && result.messagelist.length > 0) {
  142. msg = result.messagelist[0].message;
  143. }
  144. uni.showToast({
  145. title: msg,
  146. icon: 'none',
  147. duration: 3000
  148. });
  149. }
  150. } catch (err) {
  151. uni.hideLoading();
  152. uni.showToast({ title: '网络异常,续借失败', icon: 'none' });
  153. console.error('续借异常:', err);
  154. }
  155. },
  156. }
  157. };
  158. </script>
  159. <style lang="scss" scoped>
  160. .item-container {
  161. padding: 10px;
  162. background: #f5f6f7;
  163. min-height: 100vh;
  164. overflow: hidden;
  165. }
  166. .count-text {
  167. margin-bottom: 10px;
  168. font-size: 14px;
  169. color: #333;
  170. }
  171. .car-list {
  172. display: flex;
  173. align-items: flex-start;
  174. overflow-y: auto;
  175. margin-bottom: 10px;
  176. checkbox {
  177. margin-top: 15px;
  178. padding: 0 10px;
  179. }
  180. }
  181. .book-item-box {
  182. flex: 1;
  183. background: #fff;
  184. border-radius: 8px;
  185. padding: 12px;
  186. display: flex;
  187. .item-box-left {
  188. margin-right: 12px;
  189. .img-item {
  190. width: 64px;
  191. height: 90px;
  192. border-radius: 6px;
  193. }
  194. }
  195. .item-box-right { flex: 1; }
  196. .item-title { font-weight: bold; margin-bottom: 4px; }
  197. .item-author {
  198. font-size: 12px; background: #f4f6fc;
  199. padding: 2px 6px; border-radius: 4px; margin-right: 6px;
  200. }
  201. .item-desc { font-size: 12px; color: #999; margin-top: 6px; }
  202. }
  203. .bottom-placeholder { height: 60px; }
  204. .car-bottom {
  205. position: fixed; left: 0; bottom: 0; right: 0;
  206. background: #fff; padding: 12px 15px;
  207. display: flex; justify-content: space-between; align-items: center;
  208. box-shadow: 0 -2px 5px rgba(0,0,0,0.05);
  209. }
  210. .all-check { display: flex; align-items: center; }
  211. .join-btn {
  212. font-size: 14px; color: #fff;
  213. background: #01a4fe !important; border-radius: 23px;
  214. padding: 0 30px;
  215. &::after{ border: none !important; }
  216. &[disabled] { background: #ccc !important; }
  217. }
  218. .empty {
  219. padding: 0 !important;
  220. height: calc(100vh - 80px);
  221. }
  222. </style>