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

331 lines
7.4 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
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
1 month ago
2 months ago
1 month ago
2 months ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month ago
1 month 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
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 style="background-color: #fff; padding-bottom:5px;">
  3. <view class="my-search-container">
  4. <view class="my-search-wrapper">
  5. <picker
  6. mode="selector"
  7. :range="rangeText"
  8. :value="selectIndex"
  9. @change="onPickerChange"
  10. class="picker-select"
  11. >
  12. <view class="picker-display">
  13. {{ selectValueText || '请选择分类' }}
  14. <uni-icons type="arrowdown" size="14" color="#999" style="margin-left: 4px;" />
  15. </view>
  16. </picker>
  17. <uni-search-bar
  18. class="my-search-bar"
  19. @confirm="onSearch"
  20. @focus="onFocus"
  21. @blur="onBlur"
  22. @clear="onClear"
  23. @cancel="onCancel"
  24. @input="onInput"
  25. cancelButton="none"
  26. bgColor="#f7f7f7"
  27. v-model="value"
  28. placeholder="请输入搜索内容"
  29. >
  30. <uni-icons slot="clearIcon" type="clear" color="#999999" />
  31. </uni-search-bar>
  32. </view>
  33. <view class="search-btn-container" @click="onSearch">
  34. <button class="search-btn" type="primary">搜索</button>
  35. </view>
  36. <view class="filter-container">
  37. <view class="total-reslut" v-if="listData.length > 0">
  38. 搜索到 {{ total }} 条记录 {{ totalPage }} 当前第 {{ page }}
  39. </view>
  40. <!-- <view>筛选</view> -->
  41. </view>
  42. </view>
  43. <view style="padding-top: 154px;" v-if="listData.length > 0">
  44. <scroll-view
  45. scroll-y
  46. style="height: calc(100vh - 80px);"
  47. @scrolltolower="onScrollLower"
  48. >
  49. <book-list-item
  50. class="hot-list-item"
  51. v-for="(item, index) in listData"
  52. :key="index"
  53. :data="item"
  54. :ranking="index + 1"
  55. @click="onItemClick(item)"
  56. ></book-list-item>
  57. <view class="load-more" v-if="total > listData.length">
  58. 上拉加载更多...
  59. </view>
  60. <view class="load-more" v-if="total <= listData.length && listData.length > 0">
  61. 没有更多数据了
  62. </view>
  63. </scroll-view>
  64. </view>
  65. <!-- 空状态 -->
  66. <view class="empty-box" v-if="isSearched && listData.length === 0">
  67. <text>没有检索到相关数据</text>
  68. </view>
  69. </view>
  70. </template>
  71. <script>
  72. import { FetchInitScreenSetting } from '@/api/user';
  73. import { FetchBookSearch } from '@/api/book';
  74. import BookListItem from "@/components/book-list-item/book-list-item.vue";
  75. export default {
  76. components: { BookListItem },
  77. data() {
  78. return {
  79. selectValue: '',
  80. selectValueText: '',
  81. selectIndex: 0,
  82. value: '',
  83. range: [
  84. { value: '', text: "任意词" },
  85. { value: 'title', text: "题名" },
  86. { value: 'title200a', text: "正题名" },
  87. { value: 'author', text: "著者" },
  88. { value: 'isbn', text: "ISBN" },
  89. { value: 'subject', text: "主题" },
  90. { value: 'publisher', text: "出版社" },
  91. { value: 'class', text: "分类号" },
  92. { value: 'ctrlno', text: "控制号" },
  93. { value: 'orderno', text: "订购号" },
  94. { value: 'callno', text: "索书号" },
  95. ],
  96. rangeText: [],
  97. opacUrl: '',
  98. listData: [],
  99. size: 10,
  100. page: 1,
  101. total: 0,
  102. totalPage: 0,
  103. isSearched: false
  104. };
  105. },
  106. onLoad() {
  107. this.rangeText = this.range.map(item => item.text);
  108. this.selectValue = this.range[0].value;
  109. this.selectValueText = this.range[0].text;
  110. this.getOpacUrl();
  111. },
  112. // 每次进入页面都会执行
  113. onShow() {
  114. // this.resetSearchData();
  115. },
  116. methods: {
  117. // 重置搜索数据(每次进入页面清空)
  118. resetSearchData() {
  119. this.value = ''; // 清空搜索框
  120. this.listData = []; // 清空列表
  121. this.page = 1; // 重置页码
  122. this.total = 0; // 清空总数
  123. this.totalPage = 0; // 清空总页数
  124. this.isSearched = false; // 重置搜索状态
  125. // 不重置选择器,保留用户习惯
  126. },
  127. // 获取opacUrl
  128. async getOpacUrl() {
  129. try {
  130. const res = await FetchInitScreenSetting({ libcode: '1201' });
  131. this.opacUrl = res.data.opac_url?.context || '';
  132. } catch (err) {
  133. console.error('获取配置失败', err);
  134. }
  135. },
  136. // 切换检索类型
  137. onPickerChange(e) {
  138. const index = e.detail.value;
  139. this.selectIndex = index;
  140. this.selectValue = this.range[index].value;
  141. this.selectValueText = this.range[index].text;
  142. },
  143. async getBookList() {
  144. if (!this.value) {
  145. uni.showToast({ title: '请输入搜索内容', icon: 'none' });
  146. return;
  147. }
  148. if (!this.opacUrl) {
  149. uni.showToast({ title: '未获取到检索配置', icon: 'none' });
  150. return;
  151. }
  152. uni.showLoading({ title: '搜索中...' });
  153. try {
  154. const params = {
  155. opacUrl: this.opacUrl,
  156. page: this.page.toString(),
  157. query: this.value,
  158. rows: this.size.toString(),
  159. scWay: 'dim',
  160. searchWay: this.selectValue,
  161. sortOrder: 'desc',
  162. sortWay: 'score'
  163. };
  164. const res = await FetchBookSearch(params);
  165. console.log('res',res)
  166. // 精准适配你当前返回格式
  167. const apiData = res.data || {};
  168. const list = apiData.bookList || [];
  169. // 赋值总数、总页数
  170. this.total = apiData.totalCount || 0;
  171. this.totalPage = Math.ceil(this.total / this.size);
  172. // 分页拼接列表
  173. if (this.page === 1) {
  174. this.listData = list;
  175. } else {
  176. this.listData = [...this.listData, ...list];
  177. }
  178. this.isSearched = true;
  179. } catch (err) {
  180. console.error('搜索接口异常', err);
  181. this.listData = [];
  182. this.isSearched = true;
  183. } finally {
  184. uni.hideLoading();
  185. }
  186. },
  187. // 上拉加载
  188. onScrollLower() {
  189. if (this.listData.length >= this.total) return;
  190. this.page++;
  191. this.getBookList();
  192. },
  193. // 搜索
  194. onSearch() {
  195. this.page = 1;
  196. this.listData = [];
  197. this.getBookList();
  198. },
  199. // 进入详情
  200. onItemClick(item) {
  201. uni.navigateTo({
  202. url: "/subpkg/pages/book-detail/book-detail?bookrecno=" + item.bookrecno
  203. })
  204. },
  205. // 清空搜索
  206. onClear() {
  207. this.value = '';
  208. this.listData = [];
  209. this.total = 0;
  210. this.totalPage = 0;
  211. this.isSearched = false;
  212. },
  213. onFocus() {},
  214. onBlur() {},
  215. onCancel() {},
  216. onInput(val) { this.value = val; }
  217. }
  218. };
  219. </script>
  220. <style lang="scss" scoped>
  221. .my-search-container {
  222. display: flex;
  223. flex-direction: column;
  224. padding: 15px 20px;
  225. background: #fff;
  226. position: fixed;
  227. top: 0;
  228. left: 0;
  229. right: 0;
  230. z-index: 99;
  231. height: 124px;
  232. .my-search-wrapper {
  233. display: flex;
  234. align-items: center;
  235. width: 100%;
  236. padding: 5px 0;
  237. background-color: #f7f7f7;
  238. border-radius: 36px;
  239. overflow: hidden;
  240. }
  241. .picker-select {
  242. width: 60px;
  243. border-right: 1px solid #c9c9c9;
  244. }
  245. .picker-display {
  246. display: flex;
  247. align-items: center;
  248. justify-content: center;
  249. padding: 6px 0;
  250. font-size: 14px;
  251. color: #333;
  252. }
  253. .my-search-bar {
  254. flex: 1;
  255. ::v-deep .uni-searchbar {
  256. padding: 0 !important;
  257. background: transparent !important;
  258. }
  259. }
  260. .search-btn-container {
  261. width: 100%;
  262. margin-top: 10px;
  263. .search-btn {
  264. background-color: #01a4fe;
  265. font-size: 15px;
  266. border-radius: 20px;
  267. }
  268. }
  269. }
  270. .filter-container {
  271. display: flex;
  272. justify-content: flex-end;
  273. padding-top: 10px;
  274. font-size: 13px;
  275. color: #666;
  276. }
  277. .load-more {
  278. text-align: center;
  279. padding: 10px;
  280. font-size: 13px;
  281. color: #999;
  282. }
  283. .total-reslut {
  284. flex: 1;
  285. line-height: 20px;
  286. font-size: 13px;
  287. color: #01a4fe;
  288. font-weight: 400;
  289. }
  290. .empty-box {
  291. display: flex;
  292. justify-content: center;
  293. align-items: center;
  294. height: 50vh;
  295. font-size: 14px;
  296. color: #999;
  297. padding-top: 100px;
  298. }
  299. </style>