list.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. <template>
  2. <view class="container" :style="appThemeStyle">
  3. <mescroll-body ref="mescrollRef" :sticky="true" @init="mescrollInit" :down="{native: true}" @down="downCallback" :up="upOption" @up="upCallback">
  4. <!-- 页面头部 -->
  5. <view class="header">
  6. <view class="search">
  7. <search :tips="options.search ? options.search : '搜索商品'" @event="handleSearch" />
  8. </view>
  9. <!-- 切换列表显示方式 -->
  10. <!-- <view class="show-view" @click="handleShowView">
  11. <text class="iconfont icon-view-tile" v-if="showView"></text>
  12. <text class="iconfont icon-view-list" v-else></text>
  13. </view> -->
  14. </view>
  15. <!-- 排序标签 -->
  16. <view class="store-sort">
  17. <view class="sort-item" :class="{active: sortType === 'all'}" @click="handleSortType('all')">
  18. <text>全部</text>
  19. </view>
  20. <view class="sort-item" :class="{active: sortType === 'productxfky'}" @click="handleSortType('productxfky')">
  21. <text>可续费</text>
  22. </view>
  23. <!-- <view class="sort-item sort-item-price" :class="{active: sortType === 'price'}" @click="handleSortType('price')">
  24. <text>价格</text>
  25. <view class="price-arrow">
  26. <view class="icon up" :class="{active: sortType === 'price' && !sortPrice}">
  27. <text class="iconfont icon-arrow-up"></text>
  28. </view>
  29. <view class="icon down" :class="{active: sortType === 'price' && sortPrice}">
  30. <text class="iconfont icon-arrow-down"></text>
  31. </view>
  32. </view>
  33. </view> -->
  34. </view>
  35. <!-- 商品列表 -->
  36. <view class="goods-list clearfix" :class="['column-' + (showView ? '1' : '2')]">
  37. <view class="goods-item" v-for="(item, index) in list.data" :key="index" @click="buyNow(item)">
  38. <!-- 单列显示 -->
  39. <view v-if="showView" class="dis-flex">
  40. <!-- 商品图片 -->
  41. <view class="goods-item-left">
  42. <image class="image" :src="item.productpic"></image>
  43. </view>
  44. <view class="goods-item-right">
  45. <!-- 商品名称 -->
  46. <view class="goods-name">
  47. <text class="twoline-hide">{{ item.productname }} - {{ item.productmemo }}</text>
  48. </view>
  49. <view class="goods-item-desc">
  50. <!-- 商品卖点 -->
  51. <view class="desc-selling-point dis-flex">
  52. <text class="oneline-hide">{{ item.selling_point }}</text>
  53. </view>
  54. <!-- 商品销量 -->
  55. <view class="desc-goods-sales dis-flex">
  56. <text>时长:{{ item.productlimit }}{{ item.productlimittype }}</text>
  57. <text style="margin-left: 20rpx">宽带:{{ item.productdkband }}M</text>
  58. </view>
  59. <view class="desc-goods-sales dis-flex" v-if="item.productxfky">
  60. <view><u-tag text="可续费" size="mini" type="success" mode="light" /></view>
  61. </view>
  62. <!-- 商品价格 -->
  63. <view class="desc-footer">
  64. <text class="price-x">¥{{ item.productprice1 }}</text>
  65. <text class="price-y col-9" v-if="item.productprice > 0">¥{{ item.productprice }}</text>
  66. </view>
  67. </view>
  68. </view>
  69. </view>
  70. <!-- 多列显示 -->
  71. <view v-else class="">
  72. <!-- 商品图片 -->
  73. <view class="goods-image">
  74. <image class="image" mode="aspectFill" :src="item.productpic"></image>
  75. </view>
  76. <view class="detail">
  77. <!-- 商品名称 -->
  78. <view class="goods-name">
  79. <text class="twoline-hide">{{ item.productname }}</text>
  80. </view>
  81. <!-- 商品价格 -->
  82. <view class="detail-price oneline-hide">
  83. <text class="goods-price f-30 col-m">¥{{ item.goods_price_min }}</text>
  84. <text v-if="item.line_price_min > 0" class="line-price col-9 f-24">¥{{ item.line_price_min }}</text>
  85. </view>
  86. </view>
  87. </view>
  88. </view>
  89. </view>
  90. </mescroll-body>
  91. </view>
  92. </template>
  93. <script>
  94. import MescrollMixin from '@/uni_modules/mescroll-uni/components/mescroll-uni/mescroll-mixins'
  95. import * as GoodsApi from '@/api/goods'
  96. import {getEmptyPaginateObj, getMoreListData} from '@/core/app'
  97. import Search from '@/components/search'
  98. import * as AppApi from '@/api/app'
  99. import storage from '@/utils/storage'
  100. const pageSize = 15
  101. const showViewKey = 'GoodsList-ShowView'
  102. export default {
  103. components: {
  104. Search
  105. },
  106. mixins: [MescrollMixin],
  107. data() {
  108. return {
  109. showView: true, // 列表显示方式 (true列表、false平铺)
  110. sortType: 'all', // 排序类型
  111. sortPrice: false, // 价格排序 (true高到低 false低到高)
  112. options: {}, // 当前页面参数
  113. list: [], // 商品列表数据
  114. // 筛选项
  115. paramsQueue: {},
  116. // 上拉加载配置
  117. upOption: {
  118. // 首次自动执行
  119. auto: true,
  120. // 每页数据的数量; 默认10
  121. page: {size: pageSize},
  122. // 数量要大于4条才显示无更多数据
  123. noMoreSize: 4
  124. }
  125. }
  126. },
  127. /**
  128. * 生命周期函数--监听页面加载
  129. */
  130. onLoad(options) {
  131. console.log(options, 'options')
  132. // 记录options
  133. // this.options = options
  134. this.handleSortType(options.type)
  135. // 设置默认列表显示方式
  136. this.setShowView()
  137. },
  138. methods: {
  139. /**
  140. * 上拉加载的回调 (页面初始化时也会执行一次)
  141. * 其中page.num:当前页 从1开始, page.size:每页数据条数,默认10
  142. * @param {Object} page
  143. */
  144. async upCallback(page) {
  145. const app = this
  146. // 设置列表数据
  147. app
  148. .getPageData()
  149. .then((list) => {
  150. const curPageLen = list.data.length
  151. const totalSize = list.data.total
  152. app.mescroll.endBySize(curPageLen, totalSize)
  153. })
  154. .catch(() => app.mescroll.endErr())
  155. },
  156. // 设置默认列表显示方式
  157. setShowView() {
  158. // this.showView = uni.getStorageSync(showViewKey) || false
  159. this.showView = true
  160. },
  161. /**
  162. * 获取商品列表
  163. * @param {number} pageNo 页码
  164. */
  165. /**
  166. * 加载页面数据
  167. * @param {Object} callback
  168. */
  169. async getPageData(callback) {
  170. const app = this
  171. const params = {
  172. pageindex: 1,
  173. rows: 9999,
  174. 'productname.value': app.options.search,
  175. 'productagentsqym.value': storage.get('wx_qym'),
  176. ...app.paramsQueue
  177. }
  178. const {Data: res} = await AppApi.getShopList(params)
  179. app.list.data = res.Data
  180. // console.log(this.items[goodsIndex].data, '上拉加载加载页面数据')
  181. },
  182. getGoodsList(pageNo = 1) {
  183. const app = this
  184. console.log(app.options)
  185. const param = {
  186. sortType: app.sortType,
  187. sortPrice: Number(app.sortPrice),
  188. categoryId: app.options.categoryId || 0,
  189. goodsName: app.options.search || '',
  190. page: pageNo
  191. }
  192. return new Promise((resolve, reject) => {
  193. GoodsApi.list(param)
  194. .then((result) => {
  195. // 合并新数据
  196. const newList = result.data.list
  197. app.list.data = getMoreListData(newList, app.list, pageNo)
  198. resolve(newList)
  199. })
  200. .catch(reject)
  201. })
  202. },
  203. // 切换排序方式
  204. handleSortType(newSortType) {
  205. const app = this
  206. let newSortPrice = 'all'
  207. switch (newSortType) {
  208. case 'all':
  209. newSortPrice = newSortType
  210. app.paramsQueue = {}
  211. break
  212. case 'productxfky':
  213. newSortPrice = newSortType
  214. app.paramsQueue = {
  215. 'productxfky.value': 1
  216. }
  217. break
  218. default:
  219. break
  220. }
  221. app.sortType = newSortType
  222. // 刷新列表数据
  223. // app.getPageData()
  224. if (app.mescroll) {
  225. app.mescroll.resetUpScroll()
  226. }
  227. },
  228. // 切换列表显示方式
  229. handleShowView() {
  230. const app = this
  231. app.showView = !app.showView
  232. uni.setStorageSync(showViewKey, app.showView)
  233. },
  234. // 跳转商品详情页
  235. onTargetDetail(goodsId) {
  236. this.$navTo('pages/goods/detail', {goodsId})
  237. },
  238. // 立即购买
  239. buyNow(selectShop) {
  240. console.log('选择商品:', selectShop)
  241. // 跳转到订单结算页
  242. this.$navTo('pages/checkout/index', {
  243. mode: 'buyXuyue',
  244. goodsId: selectShop.productid,
  245. goodsNum: '3',
  246. goodsSkuId: '2'
  247. })
  248. },
  249. /**
  250. * 商品搜索
  251. */
  252. handleSearch() {
  253. const app = this
  254. const searchPageUrl = 'pages/search/index'
  255. // 判断来源页面
  256. let pages = getCurrentPages()
  257. if (pages.length > 1 && pages[pages.length - 2].route === searchPageUrl) {
  258. uni.navigateBack()
  259. return
  260. }
  261. // 跳转到商品搜索页
  262. this.$navTo(searchPageUrl)
  263. }
  264. },
  265. /**
  266. * 设置分享内容
  267. */
  268. onShareAppMessage() {
  269. // 构建分享参数
  270. const app = this
  271. return {
  272. title: '商品列表',
  273. path: '/pages/goods/list?' + this.$getShareUrlParams(app.options)
  274. }
  275. },
  276. /**
  277. * 分享到朋友圈
  278. * 本接口为 Beta 版本,暂只在 Android 平台支持,详见分享到朋友圈 (Beta)
  279. * https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share-timeline.html
  280. */
  281. onShareTimeline() {
  282. // 构建分享参数
  283. const app = this
  284. return {
  285. title: '商品列表',
  286. path: '/pages/goods/list?' + this.$getShareUrlParams(app.options)
  287. }
  288. }
  289. }
  290. </script>
  291. <style lang="scss" scoped>
  292. // 页面头部
  293. .header {
  294. display: flex;
  295. align-items: center;
  296. background-color: #fff;
  297. // 搜索框
  298. .search {
  299. flex: 1;
  300. }
  301. // 切换显示方式
  302. .show-view {
  303. width: 60rpx;
  304. height: 60rpx;
  305. font-size: 36rpx;
  306. color: #505050;
  307. display: flex;
  308. align-items: center;
  309. }
  310. }
  311. // 排序组件
  312. .store-sort {
  313. position: sticky;
  314. top: var(--window-top);
  315. display: flex;
  316. padding: 20rpx 0;
  317. font-size: 28rpx;
  318. background: #fff;
  319. color: #000;
  320. z-index: 99;
  321. .sort-item {
  322. flex-basis: 33.3333%;
  323. display: flex;
  324. justify-content: center;
  325. align-items: center;
  326. height: 50rpx;
  327. &.active {
  328. color: $main-bg;
  329. }
  330. }
  331. .sort-item-price .price-arrow {
  332. margin-left: 20rpx;
  333. font-size: 24rpx;
  334. color: #000;
  335. .icon {
  336. &.active {
  337. color: $main-bg;
  338. }
  339. &.up {
  340. margin-bottom: -16rpx;
  341. }
  342. &.down {
  343. margin-top: -16rpx;
  344. }
  345. }
  346. }
  347. }
  348. // 商品列表
  349. .goods-list {
  350. padding: 4rpx;
  351. box-sizing: border-box;
  352. }
  353. // 单列显示
  354. .goods-list.column-1 {
  355. .goods-item {
  356. width: 100%;
  357. height: 280rpx;
  358. margin-bottom: 12rpx;
  359. padding: 20rpx;
  360. box-sizing: border-box;
  361. background: #fff;
  362. line-height: 1.6;
  363. &:last-child {
  364. margin-bottom: 0;
  365. }
  366. }
  367. .goods-item-left {
  368. display: flex;
  369. width: 300rpx;
  370. background: #fff;
  371. align-items: center;
  372. .image {
  373. display: block;
  374. width: 240rpx;
  375. height: 240rpx;
  376. }
  377. }
  378. .goods-item-right {
  379. position: relative;
  380. flex: 1;
  381. .goods-name {
  382. margin-top: 10rpx;
  383. min-height: 68rpx;
  384. line-height: 1.3;
  385. white-space: normal;
  386. color: #484848;
  387. font-size: 26rpx;
  388. }
  389. }
  390. .goods-item-desc {
  391. margin-top: 8rpx;
  392. }
  393. .desc-selling-point {
  394. width: 400rpx;
  395. font-size: 24rpx;
  396. color: #e49a3d;
  397. }
  398. .desc-goods-sales {
  399. color: #999;
  400. font-size: 24rpx;
  401. }
  402. .desc-footer {
  403. font-size: 24rpx;
  404. .price-x {
  405. margin-right: 16rpx;
  406. color: $main-bg;
  407. font-size: 30rpx;
  408. }
  409. .price-y {
  410. text-decoration: line-through;
  411. }
  412. }
  413. }
  414. // 平铺显示
  415. .goods-list.column-2 {
  416. .goods-item {
  417. width: 50%;
  418. }
  419. }
  420. .goods-item {
  421. float: left;
  422. box-sizing: border-box;
  423. padding: 6rpx;
  424. .goods-image {
  425. position: relative;
  426. width: 100%;
  427. height: 0;
  428. padding-bottom: 100%;
  429. overflow: hidden;
  430. background: #fff;
  431. &:after {
  432. content: '';
  433. display: block;
  434. margin-top: 100%;
  435. }
  436. .image {
  437. position: absolute;
  438. width: 100%;
  439. height: 100%;
  440. top: 0;
  441. left: 0;
  442. -o-object-fit: cover;
  443. object-fit: cover;
  444. }
  445. }
  446. .detail {
  447. padding: 8rpx;
  448. background: #fff;
  449. .goods-name {
  450. min-height: 68rpx;
  451. line-height: 1.3;
  452. white-space: normal;
  453. color: #484848;
  454. font-size: 26rpx;
  455. margin-bottom: 4rpx;
  456. }
  457. .detail-price {
  458. .goods-price {
  459. margin-right: 8rpx;
  460. }
  461. .line-price {
  462. text-decoration: line-through;
  463. }
  464. }
  465. }
  466. }
  467. </style>