goodList.vue 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. <template>
  2. <!-- 商品列表 -->
  3. <view>
  4. <view v-if="tempArr.length" :style="[boxStyle]">
  5. <!-- 单列 -->
  6. <block v-if="itemStyle == 0">
  7. <view class="listA" :style="[gridGap]">
  8. <view class="item" v-for="(item, index) in tempArr" :key="index" @click="goDetail(item)">
  9. <view class="pictrue">
  10. <view v-show="item.stock===0" class="sellOut">已售罄</view>
  11. <easy-loadimage :image-src="item.image" :radius="dataConfig.contentStyle.val">
  12. </easy-loadimage>
  13. <view v-if="item.activityStyle" :style="{ backgroundImage: `url(${item.activityStyle})` }"
  14. class="border-picture"></view>
  15. </view>
  16. <view class="text-info text-add">
  17. <view>
  18. <view class="title box-line2" :style="[titleColor]">
  19. <text v-if="item.productTags && item.productTags.locationLeftTitle.length"
  20. class="font-bg-red mr10 merType bg-color">{{item.productTags.locationLeftTitle[0].tagName}}</text>
  21. <text v-if="titleShow">{{ item.name }}</text>
  22. </view>
  23. </view>
  24. <view v-if="item.productTags && item.productTags.locationUnderTitle.length">
  25. <text
  26. v-for="items in item.productTags.locationUnderTitle.length>3?item.productTags.locationUnderTitle.slice(0,3):item.productTags.locationUnderTitle"
  27. :key="items.id" class="mr10 tagSolid">{{items.tagName}}</text>
  28. </view>
  29. <view class="price acea-row row-middle" :style="[priceColor]">
  30. <view v-if="priceShow">
  31. <svip-price :svipIconStyle="svipIconStyle" :priceColor="priceColor" :productPrice="item"
  32. :svipPriceStyle="svipPriceStyle"></svip-price>
  33. </view>
  34. </view>
  35. <view class="old-price" :style="[soldColor]" v-if="soldShow">已售
  36. {{ item.sales || 0 }} {{item.unitName}}
  37. </view>
  38. </view>
  39. </view>
  40. </view>
  41. </block>
  42. <!-- 两列 -->
  43. <block v-if="itemStyle == 1">
  44. <view class="listC" :style="[gridGap]">
  45. <view class="item" :style="[contentStyle]" v-for="(item, index) in tempArr" :key="index"
  46. @click="goDetail(item)">
  47. <view class="pictrue">
  48. <view v-show="item.stock===0" class="sellOut">已售罄</view>
  49. <easy-loadimage :image-src="item.image" :radius="dataConfig.contentStyle.val">
  50. </easy-loadimage>
  51. <view v-if="item.activityStyle" :style="{ backgroundImage: `url(${item.activityStyle})` }"
  52. class="border-picture"></view>
  53. </view>
  54. <view class="text-info">
  55. <view class="title box-line2" :style="[titleColor]">
  56. <text v-if="item.productTags && item.productTags.locationLeftTitle.length"
  57. class="font-bg-red mr10 merType bg-color">{{item.productTags.locationLeftTitle[0].tagName}}</text>
  58. <text v-if="titleShow">{{ item.name }}</text>
  59. </view>
  60. <view v-if="item.productTags && item.productTags.locationUnderTitle.length">
  61. <text
  62. v-for="items in item.productTags.locationUnderTitle.length>3?item.productTags.locationUnderTitle.slice(0,3):item.productTags.locationUnderTitle"
  63. :key="items.id" class="mr10 tagSolid">{{items.tagName}}</text>
  64. </view>
  65. <view class="acea-row row-middle price" :style="[priceColor]">
  66. <view v-if="priceShow">
  67. <svip-price :svipIconStyle="svipIconStyle" :priceColor="priceColor" :productPrice="item"
  68. :svipPriceStyle="svipPriceStyle"></svip-price>
  69. </view>
  70. </view>
  71. <view class="old-price" :style="[soldColor]" v-if="soldShow">已售
  72. {{ item.sales || 0 }} {{item.unitName}}
  73. </view>
  74. </view>
  75. </view>
  76. </view>
  77. </block>
  78. <!-- 三列 -->
  79. <block v-if="itemStyle == 2">
  80. <view class="listB" :style="[gridGap]">
  81. <view class="item" v-for="(item, index) in tempArr" :key="index" @click="goDetail(item)">
  82. <view class="pictrue" :style="[contentStyle]">
  83. <view v-show="item.stock===0" class="sellOut">已售罄</view>
  84. <easy-loadimage :image-src="item.image" :radius="dataConfig.contentStyle.val">
  85. </easy-loadimage>
  86. <view v-if="item.activityStyle" :style="{ backgroundImage: `url(${item.activityStyle})` }"
  87. class="border-picture"></view>
  88. </view>
  89. <view class="text-info">
  90. <view class="title box-line2" :style="[titleColor]">
  91. <text v-if="item.productTags && item.productTags.locationLeftTitle.length"
  92. class="font-bg-red mr10 merType bg-color">{{item.productTags.locationLeftTitle[0].tagName}}</text>
  93. <text v-if="titleShow">{{ item.name }}</text>
  94. </view>
  95. <view v-if="item.productTags && item.productTags.locationUnderTitle.length">
  96. <text
  97. v-for="items in item.productTags.locationUnderTitle.length>3?item.productTags.locationUnderTitle.slice(0,3):item.productTags.locationUnderTitle"
  98. :key="items.id" class="mr10 tagSolid">{{items.tagName}}</text>
  99. </view>
  100. <view class="price" :style="[priceColor]">
  101. <view v-if="priceShow">
  102. <svip-price :svipIconStyle="svipIconStyle" :priceColor="priceColor" :productPrice="item"
  103. :svipPriceStyle="svipPriceStyle"></svip-price>
  104. </view>
  105. </view>
  106. <view class="old-price" v-if="soldShow" :style="[soldColor]">
  107. 已售 {{ item.sales || 0 }} {{ item.unitName }}
  108. </view>
  109. </view>
  110. </view>
  111. </view>
  112. </block>
  113. <!-- 大图 -->
  114. <block v-if="itemStyle == 3 && tempArr.length">
  115. <view class="listBig" :style="[gridGap]">
  116. <view class="itemBig" v-for="(item,index) in tempArr" :key="index" @click="goDetail(item)">
  117. <view class="img-box">
  118. <view v-show="item.stock===0" class="sellOut">已售罄</view>
  119. <easy-loadimage :image-src="item.image" :radius="dataConfig.contentStyle.val">
  120. </easy-loadimage>
  121. <view v-if="item.activityStyle" :style="{ backgroundImage: `url(${item.activityStyle})` }"
  122. class="border-picture"></view>
  123. </view>
  124. <view class="name box-line2" :style="[titleColor]">
  125. <text v-if="item.productTags && item.productTags.locationLeftTitle.length"
  126. class="font-bg-red merType mr10 bg-color">{{item.productTags.locationLeftTitle[0].tagName}}</text>
  127. <text v-if="titleShow">{{item.name}}</text>
  128. </view>
  129. <view style="padding: 0 8px;"
  130. v-if="item.productTags && item.productTags.locationUnderTitle.length">
  131. <text
  132. v-for="items in item.productTags.locationUnderTitle.length>3?item.productTags.locationUnderTitle.slice(0,3):item.productTags.locationUnderTitle"
  133. :key="items.id" class="mr10 tagSolid">{{items.tagName}}</text>
  134. </view>
  135. <slot name="center"></slot>
  136. <view class="acea-row row-middle price" :style="[priceColor]">
  137. <view v-if="priceShow">
  138. <svip-price :svipIconStyle="svipIconStyle" :priceColor="priceColor" :productPrice="item"
  139. :svipPriceStyle="svipPriceStyle"></svip-price>
  140. </view>
  141. </view>
  142. <view class="old-price" :style="[soldColor]" v-if="soldShow">已售
  143. {{ item.sales || 0 }} {{item.unitName}}
  144. </view>
  145. </view>
  146. </view>
  147. </block>
  148. <view class='loadingicon acea-row row-center-wrapper' :hidden='loading==false'>
  149. <text class='loading iconfont icon-jiazai'></text>
  150. </view>
  151. <!-- <view class="mores-txt" v-if="goodScroll">
  152. <text>我是有底线的</text>
  153. </view> -->
  154. </view>
  155. </view>
  156. </template>
  157. <script>
  158. // +----------------------------------------------------------------------
  159. // | CRMEB [ CRMEB赋能开发者,助力企业发展 ]
  160. // +----------------------------------------------------------------------
  161. // | Copyright (c) 2016~2025 https://www.crmeb.com All rights reserved.
  162. // +----------------------------------------------------------------------
  163. // | Licensed CRMEB并不是自由软件,未经许可不能去掉CRMEB相关版权
  164. // +----------------------------------------------------------------------
  165. // | Author: CRMEB Team <admin@crmeb.com>
  166. // +----------------------------------------------------------------------
  167. import {
  168. productList,
  169. productByidsApi
  170. } from '@/api/product.js';
  171. import {
  172. getMerProListApi
  173. } from '@/api/merchant.js';
  174. import easyLoadimage from '@/components/base/easy-loadimage.vue';
  175. import svipPrice from '@/components/svipPrice.vue';
  176. let app = getApp();
  177. export default {
  178. name: 'goodList',
  179. props: {
  180. dataConfig: {
  181. type: Object,
  182. default: () => {}
  183. },
  184. merId: { // 商户id
  185. type: Number,
  186. default: 0
  187. },
  188. },
  189. components: {
  190. easyLoadimage,
  191. svipPrice
  192. },
  193. data() {
  194. return {
  195. //普通价格
  196. svipPriceStyle: {
  197. svipBox: {
  198. height: '26rpx',
  199. borderRadius: '60rpx 56rpx 56rpx 20rpx',
  200. },
  201. icon: {
  202. height: '26rpx',
  203. fontSize: '18rpx',
  204. borderRadius: '12rpx 0 12rpx 2rpx'
  205. },
  206. price: {
  207. fontSize: '38rpx'
  208. },
  209. svipPrice: {
  210. fontSize: '22rpx'
  211. }
  212. },
  213. //svip价格
  214. svipIconStyle: {
  215. svipBox: {
  216. height: '26rpx',
  217. borderRadius: '24rpx 40rpx 40rpx 0.4rpx',
  218. },
  219. price: {
  220. fontSize: '38rpx'
  221. },
  222. svipPrice: {
  223. fontSize: '18rpx'
  224. }
  225. },
  226. tempArr: [],
  227. numConfig: this.dataConfig.numConfig.val, //展示多少条
  228. itemStyle: this.dataConfig.itemStyle.tabVal, //商品列表展示方式 单列 两列 三列
  229. type: this.dataConfig.tabConfig.tabVal || 0, //商品类型 0指定商品,1指定分类,2指定品牌,3指定商户
  230. classifyId: this.dataConfig.selectConfig ? this.dataConfig.selectConfig.activeValue : [], //分类
  231. brandId: this.dataConfig.activeValueBrand ? this.dataConfig.activeValueBrand.activeValue : [], //品牌
  232. productIds: this.dataConfig.goodsList.ids || [],
  233. homeMerId: this.dataConfig.activeValueMer ? this.dataConfig.activeValueMer.activeValue : [], //商户
  234. params: { //精品推荐分页
  235. page: 1,
  236. limit: 10,
  237. cid: '',
  238. cids: '',
  239. brandId: '',
  240. merId: '',
  241. priceOrder: '',
  242. salesOrder: ''
  243. },
  244. goodScroll: false,
  245. loading: false,
  246. themeColor:this.$options.filters.filterTheme(app.globalData.theme)
  247. };
  248. },
  249. computed: {
  250. //商品名称颜色
  251. titleColor() {
  252. return {
  253. 'color': this.dataConfig.titleColor.color[0].item,
  254. }
  255. },
  256. //最外层盒子的样式
  257. boxStyle() {
  258. return {
  259. borderRadius: this.dataConfig.bgStyle.val * 2 + 'rpx',
  260. background: `linear-gradient(${this.dataConfig.bgColor.color[0].item}, ${this.dataConfig.bgColor.color[1].item})`,
  261. margin: this.dataConfig.mbConfig.val * 2 + 'rpx' + ' ' + this.dataConfig.lrConfig.val * 2 + 'rpx' +
  262. ' ' + 0,
  263. padding: this.dataConfig.upConfig.val * 2 + 'rpx' + ' ' + '16rpx' + ' ' + this.dataConfig.downConfig
  264. .val *
  265. 2 + 'rpx'
  266. }
  267. },
  268. //图片展示样式
  269. gridGap() {
  270. return {
  271. 'grid-gap': this.dataConfig.contentConfig.val * 2 + 'rpx'
  272. }
  273. },
  274. //文章图片的圆角和高度
  275. imgStyle() {
  276. return {
  277. 'border-radius': this.dataConfig.contentStyle.val * 2 + 'rpx',
  278. }
  279. },
  280. //价格颜色
  281. priceColor() {
  282. return {
  283. 'color': this.dataConfig.themeStyleConfig.tabVal?this.dataConfig.priceColor.color[0].item:this.themeColor,
  284. }
  285. },
  286. //已售数量
  287. soldColor() {
  288. return {
  289. 'color': this.dataConfig.soldColor.color[0].item,
  290. }
  291. },
  292. //商品名称
  293. titleShow() {
  294. if (this.dataConfig.typeConfig.activeValue.includes(0)) {
  295. return true;
  296. } else {
  297. return false;
  298. }
  299. },
  300. //价格
  301. priceShow() {
  302. if (this.dataConfig.typeConfig.activeValue.includes(1)) {
  303. return true;
  304. } else {
  305. return false;
  306. }
  307. },
  308. //销量
  309. soldShow() {
  310. if (this.dataConfig.typeConfig.activeValue.includes(2)) {
  311. return true;
  312. } else {
  313. return false;
  314. }
  315. },
  316. //排序,0综合,1销量,2价格
  317. goodsSort() {
  318. return this.dataConfig.goodsSort.tabVal
  319. },
  320. //内容圆角
  321. contentStyle() {
  322. return {
  323. 'border-radius': this.dataConfig.contentStyle.val ? this.dataConfig.contentStyle.val + 'px' : '0'
  324. };
  325. },
  326. },
  327. mounted() {
  328. this.params.page = 1;
  329. this.goodScroll = false;
  330. this.tempArr = [];
  331. //类型为0时,直接加载选中的商品,不为0时根据条件加载商品列表
  332. if (this.type > 0) {
  333. this.productslist();
  334. } else {
  335. this.getProList();
  336. }
  337. },
  338. //uniapp小程序用deep重写组件样式不生效
  339. options: {
  340. styleIsolation: 'shared'
  341. },
  342. methods: {
  343. //根据商品id集合查询对应商品
  344. getProductByids(data) {
  345. uni.showLoading({
  346. title: '加载中...'
  347. });
  348. let ids = data.map((item) => item.id).join(',');
  349. productByidsApi(ids).then((res) => {
  350. this.tempArr = res.data;
  351. uni.hideLoading();
  352. })
  353. .catch(res => {
  354. uni.hideLoading();
  355. });
  356. },
  357. getProList() {
  358. if (!this.dataConfig.goodsList.list.length) return;
  359. this.getProductByids(this.dataConfig.goodsList.list);
  360. },
  361. productslist() {
  362. if (this.goodScroll) return;
  363. this.loading = true
  364. this.params.limit = this.numConfig;
  365. //如果有商户id,调用商户商品列表
  366. if (this.merId) {
  367. this.params.merId = this.merId;
  368. delete this.params.brandId;
  369. delete this.params.cid;
  370. this.params.cids = this.classifyId.join(',');
  371. } else {
  372. switch (this.type) {
  373. case 1:
  374. this.params.merId = '';
  375. this.params.brandId = '';
  376. this.params.cid = this.classifyId.join(',');
  377. break;
  378. case 2:
  379. this.params.cid = '';
  380. this.params.merId = '';
  381. this.params.brandId = this.brandId.join(',');
  382. break;
  383. case 3:
  384. this.params.cid = '';
  385. this.params.brandId = '';
  386. this.params.merId = this.homeMerId.join(',');
  387. break;
  388. }
  389. }
  390. if (this.goodsSort === 0) {
  391. this.params.priceOrder = '';
  392. this.params.salesOrder = '';
  393. } else if (this.goodsSort === 1) {
  394. this.params.priceOrder = '';
  395. this.params.salesOrder = 'desc';
  396. } else {
  397. this.params.priceOrder = 'desc';
  398. this.params.salesOrder = '';
  399. }
  400. !this.merId ? productList(this.params).then(res => {
  401. this.$set(this.params, 'page', this.params.page + 1);
  402. this.goodScroll = this.params.page > res.data.totalPage;
  403. this.tempArr = this.tempArr.concat(res.data.list || []);
  404. this.loading = false
  405. }) : getMerProListApi(this.params).then(res => {
  406. this.$set(this.params, 'page', this.params.page + 1);
  407. this.goodScroll = this.params.page > res.data.totalPage;
  408. this.tempArr = this.tempArr.concat(res.data.list || []);
  409. this.loading = false
  410. });
  411. },
  412. goDetail(item) {
  413. this.$emit('detail', item);
  414. }
  415. }
  416. };
  417. </script>
  418. <style lang="scss" scoped>
  419. .mores-txt {
  420. text-align: center;
  421. }
  422. .text-add {
  423. display: flex;
  424. flex-direction: column;
  425. justify-content: space-between;
  426. }
  427. .listBig {
  428. display: grid;
  429. grid-template-rows: auto;
  430. grid-template-columns: repeat(1, 1fr);
  431. .itemBig {
  432. width: 100%;
  433. .img-box {
  434. width: 100%;
  435. height: 710rpx;
  436. position: relative;
  437. }
  438. .name {
  439. font-size: 28rpx;
  440. font-weight: bold;
  441. margin-top: 16rpx;
  442. }
  443. .price {
  444. font-weight: bold;
  445. font-size: 12px;
  446. margin-top: 10rpx;
  447. .num {
  448. font-size: 32rpx;
  449. margin-right: 10rpx;
  450. }
  451. .old-price {
  452. color: #aaa;
  453. font-weight: normal;
  454. }
  455. }
  456. }
  457. }
  458. .listA {
  459. display: grid;
  460. grid-template-columns: repeat(1, 1fr);
  461. grid-template-rows: auto;
  462. width: 100%;
  463. .item {
  464. display: flex;
  465. width: 100%;
  466. .pictrue {
  467. width: 220rpx;
  468. height: 220rpx;
  469. position: relative;
  470. image {
  471. width: 100%;
  472. height: 100%;
  473. }
  474. }
  475. .text-info {
  476. margin-left: 20rpx;
  477. flex: 1
  478. }
  479. }
  480. }
  481. .listB {
  482. display: grid;
  483. grid-template-columns: repeat(3, 1fr);
  484. grid-template-rows: auto;
  485. width: 100%;
  486. .item {
  487. .pictrue {
  488. width: 100%;
  489. height: 220rpx;
  490. position: relative;
  491. image {
  492. width: 100%;
  493. height: 100%;
  494. }
  495. }
  496. .text-info {
  497. padding-top: 14rpx;
  498. }
  499. }
  500. }
  501. .listC {
  502. display: grid;
  503. grid-template-columns: repeat(2, 1fr);
  504. grid-template-rows: auto;
  505. width: 100%;
  506. /deep/.origin-img,
  507. /deep/.easy-loadimage {
  508. border-bottom-left-radius: 0 !important;
  509. border-bottom-right-radius: 0 !important;
  510. }
  511. .item {
  512. background-color: #fff;
  513. .pictrue {
  514. width: 100%;
  515. height: 345rpx;
  516. overflow: hidden;
  517. position: relative;
  518. image {
  519. width: 100%;
  520. height: 100%;
  521. }
  522. }
  523. .text-info {
  524. padding: 14rpx 0 14rpx 14rpx;
  525. .title {
  526. width: 300rpx;
  527. }
  528. }
  529. }
  530. }
  531. .text-info {
  532. .title {
  533. width: 100%;
  534. height: 80rpx;
  535. line-height: 40rpx;
  536. color: #333;
  537. }
  538. .old-price {
  539. font-weight: normal;
  540. font-size: 24rpx;
  541. color: #999;
  542. }
  543. .price {
  544. font-size: 36rpx;
  545. font-weight: 550;
  546. text {
  547. padding-bottom: 4rpx;
  548. font-size: 26rpx;
  549. font-weight: normal;
  550. }
  551. }
  552. }
  553. .mer_badge {
  554. padding: 0 4rpx;
  555. background-color: theme;
  556. color: #fff;
  557. font-size: 20rpx;
  558. display: inline-block;
  559. border-radius: 4rpx;
  560. line-height: 28rpx;
  561. height: 28rpx;
  562. }
  563. .box-line2 {
  564. overflow: hidden;
  565. }
  566. </style>