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

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