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

272 lines
6.7 KiB

1 month ago
  1. <template>
  2. <view class="item-container">
  3. <!-- 图书数量 + 右侧设置按钮 -->
  4. <view class="count-text">
  5. <text>图书数量 ({{ bookList.length }})</text>
  6. <text class="edit-btn" @click="toggleEdit">{{ editMode ? "完成" : "管理" }}</text>
  7. </view>
  8. <checkbox-group @change="checkboxChange">
  9. <view class="car-list" v-for="item in bookList" :key="item.isbn">
  10. <checkbox :value="item.isbn" :checked="item.checked" />
  11. <view class="book-item-box">
  12. <view class="item-box-left">
  13. <image class="img-item" :src="defaultCover" mode="aspectFill" />
  14. </view>
  15. <view class="item-box-right">
  16. <view class="item-title line-clamp-2">{{ item.title || '暂无标题' }}</view>
  17. <view class="tag-box">
  18. <text class="item-author">{{ item.author || '佚名' }}</text>
  19. </view>
  20. <view class="item-desc">
  21. 应还时间{{ item.returndate || '暂无' }}
  22. </view>
  23. </view>
  24. </view>
  25. </view>
  26. </checkbox-group>
  27. <view class="bottom-placeholder"></view>
  28. <view class="car-bottom">
  29. <!-- 全选 -->
  30. <view class="all-check" @click="handleAllCheck">
  31. <checkbox :checked="isAllChecked" />
  32. <text style="margin-left:6px">全选</text>
  33. </view>
  34. <!-- 根据编辑状态切换按钮续借 / 删除 -->
  35. <button
  36. class="join-btn"
  37. @click="editMode ? handleDelete() : handleRenew()"
  38. :disabled="!hasChecked"
  39. >
  40. {{ editMode ? "删除选中" : "一键续借" }}
  41. </button>
  42. </view>
  43. </view>
  44. </template>
  45. <script>
  46. import { FetchInitScreenSetting } from '@/api/user';
  47. import { FetchRdloanlist, FetchRenewbook } from '@/api/book';
  48. export default {
  49. data() {
  50. return {
  51. editMode: false,
  52. bookList: [],
  53. defaultCover: 'https://qiniu.aiyxlib.com/1606124577077',
  54. screenConfig: {},
  55. // 用数组维护选中项(更稳定)
  56. checkedValues: []
  57. };
  58. },
  59. onLoad() {
  60. this.getConfigAndList();
  61. },
  62. computed: {
  63. isAllChecked() {
  64. return this.bookList.length > 0 && this.checkedValues.length === this.bookList.length;
  65. },
  66. hasChecked() {
  67. return this.checkedValues.length > 0;
  68. }
  69. },
  70. methods: {
  71. async getConfigAndList() {
  72. try {
  73. const res = await FetchInitScreenSetting({ libcode: '1201' });
  74. this.screenConfig = {
  75. thirdUrl: res.data.open_lib_http?.context || '',
  76. thirdAppid: res.data.open_lib_appId?.context || '',
  77. thirdSecret: res.data.open_lib_secret?.context || '',
  78. sm4Key: res.data.sm4_key?.context || ''
  79. };
  80. this.getLendingList();
  81. } catch (err) {}
  82. },
  83. async getLendingList() {
  84. try {
  85. const params = {
  86. ...this.screenConfig,
  87. rdid: uni.getStorageSync('currentReaderCard'),
  88. };
  89. const res = await FetchRdloanlist(params);
  90. const result = typeof res.data === 'string' ? JSON.parse(res.data) : res.data;
  91. this.bookList = result.loanlist || [];
  92. // 切换列表时清空选中
  93. this.checkedValues = [];
  94. } catch (err) {
  95. uni.showToast({ title: '加载失败', icon: 'none' });
  96. }
  97. },
  98. toggleEdit() {
  99. this.editMode = !this.editMode;
  100. if (!this.editMode) {
  101. this.checkedValues = [];
  102. }
  103. },
  104. // ✅ 修复2:稳定的 checkbox 变更
  105. checkboxChange(e) {
  106. // 直接保存数组(字符串类型)
  107. this.checkedValues = e.detail.value;
  108. },
  109. handleAllCheck() {
  110. if (this.isAllChecked) {
  111. // 取消全选
  112. this.checkedValues = [];
  113. } else {
  114. // 全选:把所有 isbn 转字符串放进数组
  115. this.checkedValues = this.bookList.map(item => String(item.isbn));
  116. }
  117. },
  118. async handleRenew() {
  119. // 从 checkedValues 过滤出对应图书
  120. const checkedBooks = this.bookList.filter(item =>
  121. this.checkedValues.includes(String(item.isbn))
  122. );
  123. if (checkedBooks.length === 0) {
  124. uni.showToast({ title: '请选择要续借的图书', icon: 'none' });
  125. return;
  126. }
  127. const barcodes = checkedBooks.map(item => item.barcode).join('|');
  128. uni.showLoading({ title: '续借中...' });
  129. try {
  130. const params = {
  131. ...this.screenConfig,
  132. rdid: uni.getStorageSync('currentReaderCard'),
  133. barcode: barcodes,
  134. logtype: '30007'
  135. };
  136. console.log('续借参数', params);
  137. await FetchRenewbook(params);
  138. uni.hideLoading();
  139. uni.showToast({
  140. title: `成功续借 ${checkedBooks.length}`,
  141. icon: 'success'
  142. });
  143. this.getLendingList();
  144. } catch (err) {
  145. uni.hideLoading();
  146. uni.showToast({ title: '续借失败', icon: 'none' });
  147. }
  148. },
  149. handleDelete() {
  150. // 只保留未选中的
  151. this.bookList = this.bookList.filter(item =>
  152. !this.checkedValues.includes(String(item.isbn))
  153. );
  154. uni.showToast({
  155. title: `已删除 ${this.checkedValues.length}`,
  156. icon: "success"
  157. });
  158. this.checkedValues = [];
  159. this.editMode = false;
  160. }
  161. }
  162. };
  163. </script>
  164. <style lang="scss" scss>
  165. .item-container {
  166. padding: 10px;
  167. background: #f5f6f7;
  168. min-height: 100vh;
  169. }
  170. .count-text {
  171. margin-bottom: 10px;
  172. display: flex;
  173. justify-content: space-between;
  174. align-items: center;
  175. }
  176. .edit-btn {
  177. color: #01a4fe;
  178. font-size: 14px;
  179. }
  180. .car-list {
  181. display: flex;
  182. align-items: flex-start;
  183. margin-bottom: 10px;
  184. checkbox {
  185. margin-top: 15px;
  186. padding: 0 10px;
  187. }
  188. }
  189. .book-item-box {
  190. flex: 1;
  191. background: #fff;
  192. border-radius: 8px;
  193. padding: 12px;
  194. display: flex;
  195. .item-box-left {
  196. margin-right: 12px;
  197. .img-item {
  198. width: 64px;
  199. height: 90px;
  200. border-radius: 6px;
  201. }
  202. }
  203. .item-box-right {
  204. flex: 1;
  205. }
  206. .item-title {
  207. font-weight: bold;
  208. margin-bottom: 4px;
  209. }
  210. .item-author {
  211. font-size: 12px;
  212. background: #f4f6fc;
  213. padding: 2px 6px;
  214. border-radius: 4px;
  215. margin-right: 6px;
  216. }
  217. .item-desc {
  218. font-size: 12px;
  219. color: #999;
  220. margin-top: 6px;
  221. }
  222. }
  223. .bottom-placeholder {
  224. height: 60px;
  225. }
  226. .car-bottom {
  227. position: fixed;
  228. left: 0;
  229. bottom: 0;
  230. right: 0;
  231. background: #fff;
  232. padding: 12px 15px;
  233. display: flex;
  234. justify-content: space-between;
  235. align-items: center;
  236. box-shadow: 0 -2px 5px rgba(0, 0, 0, 0.05);
  237. }
  238. .all-check {
  239. display: flex;
  240. align-items: center;
  241. }
  242. .join-btn {
  243. font-size: 14px;
  244. color: #fff;
  245. margin: 0 !important;
  246. background-color: #01a4fe !important;
  247. border-radius: 23px;
  248. padding: 0 30px;
  249. &::after{
  250. border: none !important;
  251. }
  252. &[disabled] {
  253. background: #ccc !important;
  254. }
  255. }
  256. </style>