goods-doc-list.vue 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. <template>
  2. <view class="goods-doc-list" :class="{ hasBottom: isIphoneX }">
  3. <view class="search">
  4. <view class="search-control">
  5. <text class="iconfont icon-iconfonticonfontsousuo1"></text>
  6. <input
  7. placeholder-class="search-placeholder"
  8. placeholder="请输入商品名称/供应商名称"
  9. class="search-input"
  10. type="search"
  11. v-model="listQuery.keyword"
  12. @click="isFoucs = true"
  13. @blur="handleBlur"
  14. @input="handleInput"
  15. />
  16. </view>
  17. </view>
  18. <!-- tabs -->
  19. <tui-sticky :scrollTop="scrollTop" @sticky="handleSticky" v-if="!isSearch">
  20. <template v-slot:header>
  21. <view :class="{ hasBorder: isSitcky }">
  22. <tui-tabs
  23. :tabs="tabs"
  24. :currentTab="currentTab"
  25. sliderBgColor="#F3B574"
  26. selectedColor="#F3B574"
  27. itemWidth="50%"
  28. @change="tabChange"
  29. ></tui-tabs>
  30. </view>
  31. </template>
  32. </tui-sticky>
  33. <!-- list -->
  34. <view class="doc-list" :style="{ paddingTop: isSitcky ? '80rpx' : '' }">
  35. <view class="section" v-for="(item, index) in showList" :key="index" @click="handleRoute(item)">
  36. <image class="cover" :src="item.productImage ? item.productImage : 'https://static.caimei365.com/app/img/icon2/placeholder.png'"></image>
  37. <view class="content">
  38. <view class="title" v-if="!isSearch">{{ item.productName }}</view>
  39. <view class="title" v-else v-html="item.productName"></view>
  40. <view class="params"><text>供应商:</text>{{ item.shopName || '暂无' }}</view>
  41. <view class="params"><text>商品属性:</text>{{ item.productType === 1 ? '产品' : '仪器' }}</view>
  42. </view>
  43. </view>
  44. <view class="cm-emtpy" v-if="isEmpty">
  45. <image src="https://static.caimei365.com/app/img/icon2/PC-empty.png"></image> <text>暂无资料~</text>
  46. </view>
  47. </view>
  48. <!-- loading more -->
  49. <view v-if="showList.length > 6">
  50. <tui-loadmore :text="loadingText" :index="1" :visible="isLoading"></tui-loadmore>
  51. <tui-nomore :text="loadingText" :visible="!isLoading"></tui-nomore>
  52. </view>
  53. <!-- back top -->
  54. <!-- <tui-scroll-top :scrollTop="scrollTop"></tui-scroll-top> -->
  55. </view>
  56. </template>
  57. <script>
  58. import { mapState } from 'vuex'
  59. export default {
  60. data() {
  61. return {
  62. isLoading: false,
  63. hasMore: false,
  64. scrollTop: 0,
  65. isSitcky: false,
  66. listQuery: {
  67. keyword: '', //查询关键词
  68. productType: 0, //商品类型 0 全部 1 产品 2 仪器
  69. pageNum: 1,
  70. pageSize: 10
  71. },
  72. isFoucs: false,
  73. tabs: [{ id: 0, name: '全部' }, { id: 1, name: '产品' }, { id: 2, name: '仪器' }],
  74. currentTab: 0,
  75. searchList: [],
  76. list: [],
  77. isEmpty: false
  78. }
  79. },
  80. computed: {
  81. ...mapState(['isIphoneX']),
  82. loadingText() {
  83. if (!this.hasMore) return '没有更多了'
  84. if (this.hasMore && !this.isLoading) return '上拉加载更多'
  85. return '加载中'
  86. },
  87. isSearch() {
  88. return this.listQuery.keyword.trim() !== '' || this.isFoucs
  89. },
  90. showList() {
  91. if (this.isSearch) return this.searchList
  92. return this.list
  93. }
  94. },
  95. watch: {
  96. isSearch(val) {
  97. if (!val) this.searchList = [] //退出搜索,清空搜索列表
  98. }
  99. },
  100. onLoad() {
  101. this.getList()
  102. },
  103. methods: {
  104. // 获取商品列表
  105. getList() {
  106. this.isLoading = true
  107. this.BeautyArchive.GetArchiveProduct(this.listQuery).then(res => {
  108. console.log(res)
  109. if (res.code) return
  110. if (this.isSearch) {
  111. this.formatTitle(res.data.results) // 如果是搜索,需要高亮关键词
  112. this.searchList = [...this.searchList, ...res.data.results]
  113. this.isEmpty = this.searchList.length === 0
  114. } else {
  115. this.list = [...this.list, ...res.data.results]
  116. this.isEmpty = this.list.length === 0
  117. }
  118. this.hasMore = res.data.hasNextPage
  119. this.isLoading = false
  120. })
  121. },
  122. // 高亮文字
  123. formatTitle(list) {
  124. list.forEach((item, index) => {
  125. //正则表达式
  126. const reg = new RegExp(this.listQuery.keyword, 'g')
  127. item.productName = item.productName.replace(reg, $1 => {
  128. return `<span style="color: #F3B574;">${$1}</span>`
  129. })
  130. })
  131. },
  132. // tab切换
  133. tabChange(e) {
  134. this.currentTab = e.index
  135. this.listQuery.productType = this.currentTab
  136. // 清空列表 重置页码为1
  137. this.list = []
  138. this.listQuery.pageNum = 1
  139. this.getList()
  140. },
  141. // 吸顶
  142. handleSticky(e) {
  143. this.isSitcky = e.isFixed
  144. },
  145. // 搜索框输入
  146. handleInput(e) {
  147. if (e.detail.value.trim() === '') return
  148. this.searchList = []
  149. // 从第一页开始 , 搜索全部
  150. this.listQuery.pageNum = 1
  151. this.listQuery.productType = 0
  152. let timer = null
  153. clearTimeout(timer)
  154. timer = setTimeout(() => {
  155. this.getList()
  156. }, 500)
  157. },
  158. // 搜索框失去焦点
  159. handleBlur() {
  160. this.isFoucs = false
  161. this.listQuery.productType = this.currentTab
  162. },
  163. // 路由跳转
  164. handleRoute(item) {
  165. if (item.redirectType === 1) {
  166. this.$api.navigateTo(`/pages/goods/product?id=${item.productId}&open=caimei`)
  167. } else {
  168. this.$api.navigateTo(`/pages/goods/goods-doc-detail?id=${item.archiveId}`)
  169. }
  170. }
  171. },
  172. onPageScroll(e) {
  173. this.scrollTop = e.scrollTop
  174. },
  175. onReachBottom() {
  176. if (!this.hasMore) return
  177. let timer = null
  178. clearTimeout(timer)
  179. this.listQuery.pageNum++
  180. this.isLoading = true
  181. timer = setTimeout(() => {
  182. this.getList()
  183. }, 400)
  184. }
  185. }
  186. </script>
  187. <style lang="scss" scoped>
  188. page {
  189. height: initial;
  190. }
  191. .hasBorder {
  192. border-bottom: 1px solid #eee;
  193. }
  194. .hasBottom {
  195. padding-bottom: 60rpx;
  196. }
  197. .doc-list {
  198. padding: 0 24rpx;
  199. .section {
  200. display: flex;
  201. justify-content: space-between;
  202. align-items: center;
  203. padding: 32rpx 0;
  204. border-bottom: 1rpx solid #f0f0f0;
  205. &:last-child {
  206. border-bottom: 0;
  207. padding-bottom: 0;
  208. }
  209. }
  210. .cover {
  211. width: 180rpx;
  212. height: 180rpx;
  213. border-radius: 8rpx;
  214. }
  215. .content {
  216. width: 494rpx;
  217. margin-left: 24rpx;
  218. .title {
  219. height: 74rpx;
  220. margin-bottom: 34rpx;
  221. font-size: 26rpx;
  222. line-height: 37rpx;
  223. color: #333333;
  224. word-break: break-all;
  225. overflow: hidden; /*超出隐藏*/
  226. text-overflow: ellipsis; /*文本溢出时显示省略标记*/
  227. display: -webkit-box; /*设置弹性盒模型*/
  228. -webkit-line-clamp: 2; /*文本占的行数,如果要设置2行加...则设置为2*/
  229. -webkit-box-orient: vertical;
  230. text {
  231. color: #F3B574;
  232. }
  233. }
  234. .params {
  235. margin-top: 8rpx;
  236. font-size: 22rpx;
  237. color: #333333;
  238. text {
  239. color: #999999;
  240. }
  241. }
  242. }
  243. }
  244. .search-placeholder {
  245. color: #b2b2b2;
  246. font-size: 28rpx;
  247. }
  248. .search {
  249. display: flex;
  250. justify-content: center;
  251. width: 750rpx;
  252. padding: 24rpx 0 0;
  253. background: #fff;
  254. .search-control {
  255. display: flex;
  256. align-items: center;
  257. justify-content: flex-start;
  258. width: 702rpx;
  259. border-radius: 40rpx;
  260. background: #f7f7f7;
  261. overflow: hidden;
  262. .search-input {
  263. flex: 1;
  264. border: 0;
  265. height: 66rpx;
  266. font-size: 28rpx;
  267. color: #333333;
  268. }
  269. .iconfont {
  270. font-size: 36rpx;
  271. margin: 0 20rpx;
  272. color: #b2b2b2;
  273. }
  274. }
  275. }
  276. .cm-emtpy {
  277. width: 100%;
  278. padding-top: 40vw;
  279. display: flex;
  280. justify-content: center;
  281. align-items: center;
  282. flex-direction: column;
  283. image {
  284. display: block;
  285. width: 260rpx;
  286. height: 260rpx;
  287. }
  288. text {
  289. display: block;
  290. margin-top: 10rpx;
  291. font-size: 26rpx;
  292. font-weight: 400;
  293. color: #999999;
  294. }
  295. }
  296. </style>