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.

542 lines
14 KiB

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