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

328 lines
7.5 KiB

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