四零语境前端代码仓库
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.

320 lines
6.7 KiB

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
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
1 month ago
1 month ago
1 month ago
1 month ago
  1. <template>
  2. <view class="search-container">
  3. <!-- 顶部搜索栏 -->
  4. <view class="search-header">
  5. <uv-search
  6. v-model="searchKeyword"
  7. placeholder="请输入内容"
  8. :show-action="true"
  9. action-text="搜索"
  10. :action-style="{
  11. color: '#fff',
  12. backgroundColor: '#06DADC',
  13. borderRadius: '198rpx',
  14. width: '100rpx',
  15. height: '64rpx',
  16. textAlign: 'center',
  17. fontSize: '26rpx',
  18. lineHeight: '64rpx',
  19. }"
  20. @search="handleSearch"
  21. @custom="handleSearch"
  22. @clear="handleSearch"
  23. ></uv-search>
  24. <!-- 分类标签栏 -->
  25. <view class="category-tabs">
  26. <scroll-view scroll-x class="tab-scroll">
  27. <view class="tab-list">
  28. <view
  29. v-for="(tab, index) in categoryTabs"
  30. :key="index"
  31. class="tab-item"
  32. :class="{ active: currentTab === index }"
  33. @click="switchTab(index)"
  34. >
  35. {{ tab.title }}
  36. </view>
  37. </view>
  38. </scroll-view>
  39. </view>
  40. </view>
  41. <!-- 搜索结果列表 -->
  42. <view class="search-results">
  43. <view
  44. v-for="(book, index) in list"
  45. :key="index"
  46. class="book-item"
  47. @click="goToDetail(book)"
  48. >
  49. <view class="book-cover">
  50. <image :src="book.booksImg" mode="aspectFill"></image>
  51. </view>
  52. <view class="book-info">
  53. <view class="book-title">{{ book.booksName }}</view>
  54. <view class="book-author">{{ book.booksAuthor }}</view>
  55. <view class="book-meta">
  56. <view class="book-duration">
  57. <image src="/static/play-icon.png" mode="aspectFill" class="book-icon"></image>
  58. <text>{{ book.duration }}</text>
  59. </view>
  60. <view class="book-membership" :class="classMap[book.vipInfo.title]">
  61. {{ book.vipInfo.title }}
  62. </view>
  63. </view>
  64. </view>
  65. </view>
  66. <uv-loading-icon text="加载中" textSize="30rpx" v-if="isLoading" ></uv-loading-icon>
  67. <uv-empty v-else-if="list.length === 0" ></uv-empty>
  68. </view>
  69. </view>
  70. </template>
  71. <script>
  72. import MixinList from '@/mixins/list.js'
  73. export default {
  74. mixins: [MixinList],
  75. data() {
  76. return {
  77. mixinListApi: 'book.list',
  78. // 自定义onShow
  79. mixinListConfig: {
  80. customOnShow: true,
  81. },
  82. searchKeyword: '',
  83. label : '',
  84. currentTab: 0,
  85. categoryTabs: [ ],
  86. // 类型引射表
  87. classMap: {
  88. '蕾朵会员': 'book-membership-premium',
  89. '盛放会员': 'book-membership-vip',
  90. '萌芽会员': 'book-membership-basic',
  91. },
  92. bookList: [
  93. ]
  94. }
  95. },
  96. methods: {
  97. mixinSetParams(){
  98. const params = {
  99. category: this.categoryTabs[this.currentTab].id,
  100. }
  101. if(this.label){
  102. params.label = this.label
  103. }
  104. if(this.searchKeyword){
  105. params.title = this.searchKeyword
  106. }
  107. return params
  108. },
  109. handleSearch() {
  110. // console.log('搜索:', this.searchKeyword)
  111. this.list = []
  112. this.initPage()
  113. this.getList(true)
  114. // 这里添加搜索逻辑
  115. },
  116. switchTab(index) {
  117. this.currentTab = index
  118. // console.log('切换分类:', this.categoryTabs[index])
  119. this.list = []
  120. this.initPage()
  121. this.getList(true)
  122. // 这里添加分类切换逻辑
  123. },
  124. goToDetail(book) {
  125. uni.navigateTo({
  126. url: '/subPages/home/directory?id=' + book.id
  127. })
  128. },
  129. // 获取书籍分类
  130. async getCategory() {
  131. const categoryRes = await this.$api.book.category()
  132. if (categoryRes.code === 200){
  133. this.categoryTabs = categoryRes.result.map(item => ({
  134. title:item.title,
  135. id: item.id
  136. }))
  137. }
  138. },
  139. },
  140. onLoad(options) {
  141. if (options.label){
  142. this.label = options.label
  143. }
  144. },
  145. async onShow() {
  146. await this.getCategory()
  147. this.getList()
  148. }
  149. }
  150. </script>
  151. <style scoped lang="scss">
  152. .search-container {
  153. background: #fff;
  154. min-height: 100vh;
  155. }
  156. .search-header {
  157. padding: 10rpx 32rpx 6rpx;
  158. background: #fff;
  159. position: sticky;
  160. top: 0;
  161. left: 0;
  162. right: 0;
  163. z-index: 999;
  164. }
  165. .category-tabs {
  166. background: #fff;
  167. // border-bottom: 1rpx solid #f0f0f0;
  168. .tab-scroll {
  169. white-space: nowrap;
  170. }
  171. .tab-list {
  172. display: flex;
  173. padding: 0 32rpx;
  174. }
  175. .tab-item {
  176. flex-shrink: 0;
  177. padding: 24rpx 22rpx;
  178. font-size: 32rpx;
  179. color: $secondary-text-color;
  180. position: relative;
  181. &.active {
  182. color: $primary-text-color;
  183. font-weight: 600;
  184. &::after {
  185. content: '';
  186. position: absolute;
  187. bottom: 0;
  188. left: 50%;
  189. transform: translateX(-50%);
  190. width: 22rpx;
  191. height: 4rpx;
  192. background: $primary-text-color;
  193. border-radius: 2rpx;
  194. }
  195. }
  196. }
  197. }
  198. .search-results {
  199. padding: 32rpx;
  200. display: flex;
  201. flex-direction: column;
  202. gap: 32rpx;
  203. }
  204. .book-item {
  205. display: flex;
  206. align-items: center;
  207. // border-bottom: 1rpx solid #f5f5f5;
  208. background: #F8F8F8;
  209. // width: 686rpx;
  210. height: 212rpx;
  211. gap: 16rpx;
  212. border-radius: 16rpx;
  213. padding: 0rpx 16rpx;
  214. &:last-child {
  215. border-bottom: none;
  216. }
  217. .book-cover {
  218. width: 136rpx;
  219. height: 180rpx;
  220. border-radius: 16rpx;
  221. overflow: hidden;
  222. margin-right: 16rpx;
  223. z-index: 1;
  224. image {
  225. width: 100%;
  226. height: 100%;
  227. }
  228. }
  229. .book-info {
  230. flex: 1;
  231. display: flex;
  232. flex-direction: column;
  233. justify-content: space-between;
  234. }
  235. .book-title {
  236. font-size: 32rpx;
  237. font-weight: 600;
  238. color: $primary-text-color;
  239. line-height: 48rpx;
  240. letter-spacing: 0;
  241. margin-bottom: 12rpx;
  242. overflow: hidden;
  243. text-overflow: ellipsis;
  244. }
  245. .book-author {
  246. font-size: 24rpx;
  247. color: $secondary-text-color;
  248. margin-bottom: 16rpx;
  249. overflow: hidden;
  250. text-overflow: ellipsis;
  251. white-space: nowrap;
  252. }
  253. .book-meta {
  254. display: flex;
  255. align-items: center;
  256. justify-content: space-between;
  257. }
  258. .book-duration {
  259. display: flex;
  260. align-items: center;
  261. font-size: 22rpx;
  262. color: #999;
  263. .book-icon{
  264. width: 18rpx;
  265. height: 18rpx;
  266. }
  267. text {
  268. margin-left: 8rpx;
  269. }
  270. }
  271. .book-membership {
  272. padding: 8rpx 16rpx;
  273. border-radius: 8rpx;
  274. font-size: 24rpx;
  275. color: #211508;
  276. }
  277. }
  278. .book-membership-premium {
  279. background: #E9F1FF;
  280. border: 2rpx solid #C4DAFF
  281. }
  282. .book-membership-vip {
  283. background: #FFF4E9;
  284. border: 2rpx solid #FFE2C4
  285. }
  286. .book-membership-basic {
  287. background: #FFE9E9;
  288. border: 2rpx solid #FFDBC4
  289. }
  290. </style>