s-goods-column.vue 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  1. <!-- 页面 -->
  2. <template>
  3. <view class="ss-goods-wrap">
  4. <!-- xs卡片:横向紧凑型,一行放两个,图片左内容右边 -->
  5. <view
  6. v-if="size === 'xs'"
  7. class="xs-goods-card ss-flex ss-col-stretch"
  8. :style="[elStyles]"
  9. @tap="onClick"
  10. >
  11. <view v-if="tagStyle.show" class="tag-icon-box">
  12. <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
  13. </view>
  14. <image class="xs-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="aspectFit" />
  15. <view
  16. v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
  17. class="xs-goods-content ss-flex-col ss-row-around"
  18. >
  19. <view
  20. v-if="goodsFields.title?.show || goodsFields.name?.show"
  21. class="xs-goods-title ss-line-1"
  22. :style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
  23. >
  24. {{ data.title || data.name }}
  25. </view>
  26. <!-- 活动信息 -->
  27. <view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
  28. <view class="card" v-if="discountText">{{ discountText }}</view>
  29. <view
  30. class="card2"
  31. v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
  32. :key="item"
  33. >
  34. {{ item }}
  35. </view>
  36. </view>
  37. <view
  38. v-if="goodsFields.price?.show"
  39. class="xs-goods-price font-OPPOSANS"
  40. :style="[{ color: goodsFields.price.color }]"
  41. >
  42. <!-- 活动价格 -->
  43. <text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
  44. {{ data.point }}积分
  45. {{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
  46. </text>
  47. <template v-else>
  48. <text class="price-unit ss-font-24">{{ priceUnit }}</text>
  49. <text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
  50. <text v-else>
  51. {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
  52. </text>
  53. </template>
  54. </view>
  55. </view>
  56. </view>
  57. <!-- sm卡片:竖向紧凑,一行放三个,图上内容下 -->
  58. <view v-if="size === 'sm'" class="sm-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
  59. <view v-if="tagStyle.show" class="tag-icon-box">
  60. <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
  61. </view>
  62. <image
  63. class="sm-img-box"
  64. :src="sheep.$url.cdn(data.image || data.picUrl)"
  65. mode="aspectFill"
  66. ></image>
  67. <view
  68. v-if="goodsFields.title?.show || goodsFields.name?.show || goodsFields.price?.show"
  69. class="sm-goods-content"
  70. :style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
  71. >
  72. <view
  73. v-if="goodsFields.title?.show || goodsFields.name?.show"
  74. class="sm-goods-title ss-line-1 ss-m-b-16"
  75. >
  76. {{ data.title || data.name }}
  77. </view>
  78. <!-- 活动信息 -->
  79. <view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
  80. <view class="card" v-if="discountText">{{ discountText }}</view>
  81. <view
  82. class="card2"
  83. v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
  84. :key="item"
  85. >
  86. {{ item }}
  87. </view>
  88. </view>
  89. <view
  90. v-if="goodsFields.price?.show"
  91. class="sm-goods-price font-OPPOSANS"
  92. :style="[{ color: goodsFields.price.color }]"
  93. >
  94. <!-- 活动价格 -->
  95. <text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
  96. {{ data.point }}积分
  97. {{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
  98. </text>
  99. <template v-else>
  100. <text class="price-unit ss-font-24">{{ priceUnit }}</text>
  101. <text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
  102. <text v-else>
  103. {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
  104. </text>
  105. </template>
  106. </view>
  107. </view>
  108. </view>
  109. <!-- md卡片:竖向,一行放两个,图上内容下 -->
  110. <view v-if="size === 'md'" class="md-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
  111. <view v-if="tagStyle.show" class="tag-icon-box">
  112. <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)" />
  113. </view>
  114. <image class="md-img-box" :src="sheep.$url.cdn(data.image || data.picUrl)" mode="widthFix" />
  115. <view
  116. class="md-goods-content ss-flex-col ss-row-around ss-p-b-20 ss-p-t-20 ss-p-x-16"
  117. :id="elId"
  118. >
  119. <view
  120. v-if="goodsFields.title?.show || goodsFields.name?.show"
  121. class="md-goods-title ss-line-1"
  122. :style="[{ color: titleColor, width: titleWidth ? titleWidth + 'rpx' : '' }]"
  123. >
  124. {{ data.title || data.name }}
  125. </view>
  126. <view
  127. v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
  128. class="md-goods-subtitle ss-m-t-16 ss-line-1"
  129. :style="[{ color: subTitleColor, background: subTitleBackground }]"
  130. >
  131. {{ data.subtitle || data.introduction }}
  132. </view>
  133. <slot name="activity">
  134. <view v-if="data.promos?.length" class="tag-box ss-flex-wrap ss-flex ss-col-center">
  135. <view
  136. class="activity-tag ss-m-r-10 ss-m-t-16"
  137. v-for="item in data.promos"
  138. :key="item.id"
  139. >
  140. {{ item.title }}
  141. </view>
  142. </view>
  143. </slot>
  144. <!-- 活动信息 -->
  145. <view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
  146. <view class="card" v-if="discountText">{{ discountText }}</view>
  147. <view
  148. class="card2"
  149. v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
  150. :key="item"
  151. >
  152. {{ item }}
  153. </view>
  154. </view>
  155. <view class="ss-flex ss-col-bottom">
  156. <view
  157. v-if="goodsFields.price?.show"
  158. class="md-goods-price ss-m-t-16 font-OPPOSANS ss-m-r-10"
  159. :style="[{ color: goodsFields.price.color }]"
  160. >
  161. <!-- 活动价格 -->
  162. <text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
  163. {{ data.point }}积分
  164. {{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
  165. </text>
  166. <template v-else>
  167. <text class="price-unit ss-font-24">{{ priceUnit }}</text>
  168. <text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
  169. <text v-else>
  170. {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
  171. </text>
  172. </template>
  173. </view>
  174. <view
  175. v-if="
  176. (goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
  177. (data.original_price > 0 || data.marketPrice > 0)
  178. "
  179. class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
  180. :style="[{ color: originPriceColor }]"
  181. >
  182. <text class="price-unit ss-font-20">{{ priceUnit }}</text>
  183. <view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
  184. </view>
  185. </view>
  186. <view class="ss-m-t-16 ss-flex ss-col-center ss-flex-wrap">
  187. <view class="sales-text">{{ salesAndStock }}</view>
  188. </view>
  189. </view>
  190. <slot name="cart">
  191. <view class="cart-box ss-flex ss-col-center ss-row-center">
  192. <image class="cart-icon" src="/static/img/shop/tabbar/category2.png" mode="" />
  193. </view>
  194. </slot>
  195. </view>
  196. <!-- lg卡片:横向型,一行放一个,图片左内容右边 -->
  197. <view
  198. v-if="size === 'lg'"
  199. class="lg-goods-card ss-flex ss-col-stretch"
  200. :style="[elStyles]"
  201. @tap="onClick"
  202. >
  203. <view v-if="tagStyle.show" class="tag-icon-box">
  204. <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)"></image>
  205. </view>
  206. <view v-if="seckillTag" class="seckill-tag ss-flex ss-row-center">秒杀</view>
  207. <view v-if="grouponTag" class="groupon-tag ss-flex ss-row-center">
  208. <view class="tag-icon">拼团</view>
  209. </view>
  210. <image
  211. class="lg-img-box"
  212. :src="sheep.$url.cdn(data.image || data.picUrl)"
  213. mode="aspectFill"
  214. />
  215. <view class="lg-goods-content ss-flex-1 ss-flex-col ss-row-between ss-p-b-10 ss-p-t-20">
  216. <view>
  217. <view
  218. v-if="goodsFields.title?.show || goodsFields.name?.show"
  219. class="lg-goods-title ss-line-2"
  220. :style="[{ color: titleColor }]"
  221. >
  222. {{ data.title || data.name }}
  223. </view>
  224. <view
  225. v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
  226. class="lg-goods-subtitle ss-m-t-10 ss-line-1"
  227. :style="[{ color: subTitleColor, background: subTitleBackground }]"
  228. >
  229. {{ data.subtitle || data.introduction }}
  230. </view>
  231. </view>
  232. <view>
  233. <slot name="activity">
  234. <view v-if="data.promos?.length" class="tag-box ss-flex ss-col-center">
  235. <view class="activity-tag ss-m-r-10" v-for="item in data.promos" :key="item.id">
  236. {{ item.title }}
  237. </view>
  238. </view>
  239. </slot>
  240. <!-- 活动信息 -->
  241. <view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
  242. <view class="card" v-if="discountText">{{ discountText }}</view>
  243. <view
  244. class="card2"
  245. v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
  246. :key="item"
  247. >
  248. {{ item }}
  249. </view>
  250. </view>
  251. <view v-if="goodsFields.price?.show" class="ss-flex ss-col-bottom font-OPPOSANS">
  252. <view class="sl-goods-price ss-m-r-12" :style="[{ color: goodsFields.price.color }]">
  253. <!-- 活动价格 -->
  254. <text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
  255. {{ data.point }}积分
  256. {{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
  257. </text>
  258. <template v-else>
  259. <text class="price-unit ss-font-24">{{ priceUnit }}</text>
  260. <text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
  261. <text v-else>
  262. {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
  263. </text>
  264. </template>
  265. </view>
  266. <view
  267. v-if="
  268. (goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
  269. (data.original_price > 0 || data.marketPrice > 0)
  270. "
  271. class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
  272. :style="[{ color: originPriceColor }]"
  273. >
  274. <text class="price-unit ss-font-20">{{ priceUnit }}</text>
  275. <view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
  276. </view>
  277. </view>
  278. <view class="ss-m-t-8 ss-flex ss-col-center ss-flex-wrap">
  279. <view class="sales-text">{{ salesAndStock }}</view>
  280. </view>
  281. </view>
  282. </view>
  283. <slot name="cart">
  284. <view class="buy-box ss-flex ss-col-center ss-row-center" v-if="buttonShow"> 去购买</view>
  285. </slot>
  286. </view>
  287. <!-- sl卡片:竖向型,一行放一个,图片上内容下边 -->
  288. <view v-if="size === 'sl'" class="sl-goods-card ss-flex-col" :style="[elStyles]" @tap="onClick">
  289. <view v-if="tagStyle.show" class="tag-icon-box">
  290. <image class="tag-icon" :src="sheep.$url.cdn(tagStyle.src || tagStyle.imgUrl)" />
  291. </view>
  292. <image
  293. class="sl-img-box"
  294. :src="sheep.$url.cdn(data.image || data.picUrl)"
  295. mode="aspectFill"
  296. />
  297. <view class="sl-goods-content">
  298. <view>
  299. <view
  300. v-if="goodsFields.title?.show || goodsFields.name?.show"
  301. class="sl-goods-title ss-line-1"
  302. :style="[{ color: titleColor }]"
  303. >
  304. {{ data.title || data.name }}
  305. </view>
  306. <view
  307. v-if="goodsFields.subtitle?.show || goodsFields.introduction?.show"
  308. class="sl-goods-subtitle ss-m-t-16"
  309. :style="[{ color: subTitleColor, background: subTitleBackground }]"
  310. >
  311. {{ data.subtitle || data.introduction }}
  312. </view>
  313. </view>
  314. <view>
  315. <slot name="activity">
  316. <view v-if="data.promos?.length" class="tag-box ss-flex ss-col-center ss-flex-wrap">
  317. <view
  318. class="activity-tag ss-m-r-10 ss-m-t-16"
  319. v-for="item in data.promos"
  320. :key="item.id"
  321. >
  322. {{ item.title }}
  323. </view>
  324. </view>
  325. </slot>
  326. <!-- 活动信息 -->
  327. <view class="iconBox" v-if="data.promotionType > 0 || data.rewardActivity">
  328. <view class="card" v-if="discountText">{{ discountText }}</view>
  329. <view
  330. class="card2"
  331. v-for="item in getRewardActivityRuleItemDescriptions(data.rewardActivity).slice(0, 1)"
  332. :key="item"
  333. >
  334. {{ item }}
  335. </view>
  336. </view>
  337. <view v-if="goodsFields.price?.show" class="ss-flex ss-col-bottom font-OPPOSANS">
  338. <view class="sl-goods-price ss-m-r-12" :style="[{ color: goodsFields.price.color }]">
  339. <!-- 活动价格 -->
  340. <text v-if="data.activityType && data.activityType === PromotionActivityTypeEnum.POINT.type">
  341. {{ data.point }}积分
  342. {{ !data.pointPrice || data.pointPrice === 0 ? '' : `+${fen2yuan(data.pointPrice)}元` }}
  343. </text>
  344. <template v-else>
  345. <text class="price-unit ss-font-24">{{ priceUnit }}</text>
  346. <text v-if="data.promotionPrice > 0">{{ fen2yuan(data.promotionPrice) }}</text>
  347. <text v-else>
  348. {{ isArray(data.price) ? fen2yuan(data.price[0]) : fen2yuan(data.price) }}
  349. </text>
  350. </template>
  351. </view>
  352. <view
  353. v-if="
  354. (goodsFields.original_price?.show || goodsFields.marketPrice?.show) &&
  355. (data.original_price > 0 || data.marketPrice > 0)
  356. "
  357. class="goods-origin-price ss-m-t-16 font-OPPOSANS ss-flex"
  358. :style="[{ color: originPriceColor }]"
  359. >
  360. <text class="price-unit ss-font-20">{{ priceUnit }}</text>
  361. <view class="ss-m-l-8">{{ fen2yuan(data.marketPrice) }}</view>
  362. </view>
  363. </view>
  364. <view class="ss-m-t-16 ss-flex ss-flex-wrap">
  365. <view class="sales-text">{{ salesAndStock }}</view>
  366. </view>
  367. </view>
  368. </view>
  369. <slot name="cart">
  370. <view class="buy-box ss-flex ss-col-center ss-row-center">去购买</view>
  371. </slot>
  372. </view>
  373. </view>
  374. </template>
  375. <script setup>
  376. /**
  377. * 商品卡片
  378. *
  379. * @property {Array} size = [xs | sm | md | lg | sl ] - 列表数据
  380. * @property {String} tag - md及以上才有
  381. * @property {String} img - 图片
  382. * @property {String} background - 背景色
  383. * @property {String} topRadius - 上圆角
  384. * @property {String} bottomRadius - 下圆角
  385. * @property {String} title - 标题
  386. * @property {String} titleColor - 标题颜色
  387. * @property {Number} titleWidth = 0 - 标题宽度,默认0,单位rpx
  388. * @property {String} subTitle - 副标题
  389. * @property {String} subTitleColor - 副标题颜色
  390. * @property {String} subTitleBackground - 副标题背景
  391. * @property {String | Number} price - 价格
  392. * @property {String} priceColor - 价格颜色
  393. * @property {String | Number} originPrice - 原价/划线价
  394. * @property {String} originPriceColor - 原价颜色
  395. * @property {String | Number} sales - 销售数量
  396. * @property {String} salesColor - 销售数量颜色
  397. *
  398. * @slots activity - 活动插槽
  399. * @slots cart - 购物车插槽,默认包含文字,背景色,文字颜色 || 图片 || 行为
  400. *
  401. * @event {Function()} click - 点击卡片
  402. *
  403. */
  404. import { computed, getCurrentInstance, nextTick, onMounted } from 'vue';
  405. import sheep from '@/sheep';
  406. import {
  407. fen2yuan,
  408. formatExchange,
  409. formatSales,
  410. formatStock,
  411. getRewardActivityRuleItemDescriptions,
  412. } from '@/sheep/hooks/useGoods';
  413. import { isArray } from 'lodash-es';
  414. import { PromotionActivityTypeEnum } from '@/sheep/util/const';
  415. // 接收参数
  416. const props = defineProps({
  417. goodsFields: {
  418. type: [Array, Object],
  419. default() {
  420. return {
  421. // 商品价格
  422. price: {
  423. show: true,
  424. },
  425. // 库存
  426. stock: {
  427. show: true,
  428. },
  429. // 商品名称
  430. name: {
  431. show: true,
  432. },
  433. // 商品介绍
  434. introduction: {
  435. show: true,
  436. },
  437. // 市场价
  438. marketPrice: {
  439. show: true,
  440. },
  441. // 销量
  442. salesCount: {
  443. show: true,
  444. },
  445. };
  446. },
  447. },
  448. tagStyle: {
  449. type: Object,
  450. default: () => ({}),
  451. },
  452. data: {
  453. type: Object,
  454. default: () => ({}),
  455. },
  456. size: {
  457. type: String,
  458. default: 'sl',
  459. },
  460. background: {
  461. type: String,
  462. default: '',
  463. },
  464. topRadius: {
  465. type: Number,
  466. default: 0,
  467. },
  468. bottomRadius: {
  469. type: Number,
  470. default: 0,
  471. },
  472. titleWidth: {
  473. type: Number,
  474. default: 0,
  475. },
  476. titleColor: {
  477. type: String,
  478. default: '#333',
  479. },
  480. priceColor: {
  481. type: String,
  482. default: '',
  483. },
  484. originPriceColor: {
  485. type: String,
  486. default: '#C4C4C4',
  487. },
  488. priceUnit: {
  489. type: String,
  490. default: '¥',
  491. },
  492. subTitleColor: {
  493. type: String,
  494. default: '#999999',
  495. },
  496. subTitleBackground: {
  497. type: String,
  498. default: '',
  499. },
  500. buttonShow: {
  501. type: Boolean,
  502. default: true,
  503. },
  504. seckillTag: {
  505. type: Boolean,
  506. default: false,
  507. },
  508. grouponTag: {
  509. type: Boolean,
  510. default: false,
  511. },
  512. });
  513. // 优惠文案
  514. const discountText = computed(() => {
  515. const promotionType = props.data.promotionType;
  516. if (promotionType === 4) {
  517. return '限时优惠';
  518. } else if (promotionType === 6) {
  519. return '会员价';
  520. }
  521. return undefined;
  522. });
  523. // 组件样式
  524. const elStyles = computed(() => {
  525. return {
  526. background: props.background,
  527. 'border-top-left-radius': props.topRadius + 'px',
  528. 'border-top-right-radius': props.topRadius + 'px',
  529. 'border-bottom-left-radius': props.bottomRadius + 'px',
  530. 'border-bottom-right-radius': props.bottomRadius + 'px',
  531. };
  532. });
  533. // 格式化销量、库存信息
  534. const salesAndStock = computed(() => {
  535. let text = [];
  536. if (props.goodsFields.salesCount?.show) {
  537. if (props.data.activityType && props.data.activityType === PromotionActivityTypeEnum.POINT.type) {
  538. text.push(formatExchange(props.data.sales_show_type, (props.data.pointTotalStock || 0) - (props.data.pointStock || 0)));
  539. }else {
  540. text.push(formatSales(props.data.sales_show_type, props.data.salesCount));
  541. }
  542. }
  543. if (props.goodsFields.stock?.show) {
  544. if (props.data.activityType && props.data.activityType === PromotionActivityTypeEnum.POINT.type) {
  545. text.push(formatStock(props.data.stock_show_type, props.data.pointTotalStock));
  546. }else {
  547. text.push(formatStock(props.data.stock_show_type, props.data.stock));
  548. }
  549. }
  550. return text.join(' | ');
  551. });
  552. // 返回事件
  553. const emits = defineEmits(['click', 'getHeight']);
  554. const onClick = () => {
  555. emits('click');
  556. };
  557. // 获取卡片实时高度
  558. const { proxy } = getCurrentInstance();
  559. const elId = `sheep_${Math.ceil(Math.random() * 10e5).toString(36)}`;
  560. function getGoodsPriceCardWH() {
  561. if (props.size === 'md') {
  562. const view = uni.createSelectorQuery().in(proxy);
  563. view.select(`#${elId}`).fields({
  564. size: true,
  565. scrollOffset: true,
  566. });
  567. view.exec((data) => {
  568. let totalHeight = 0;
  569. const goodsPriceCard = data[0];
  570. if (props.data.image_wh) {
  571. totalHeight =
  572. (goodsPriceCard.width / props.data.image_wh.w) * props.data.image_wh.h +
  573. goodsPriceCard.height;
  574. } else {
  575. totalHeight = goodsPriceCard.width;
  576. }
  577. emits('getHeight', totalHeight);
  578. });
  579. }
  580. }
  581. onMounted(() => {
  582. nextTick(() => {
  583. getGoodsPriceCardWH();
  584. });
  585. });
  586. </script>
  587. <style lang="scss" scoped>
  588. .tag-icon-box {
  589. position: absolute;
  590. left: 0;
  591. top: 0;
  592. z-index: 2;
  593. .tag-icon {
  594. width: 72rpx;
  595. height: 44rpx;
  596. }
  597. }
  598. .seckill-tag {
  599. position: absolute;
  600. left: 0;
  601. top: 0;
  602. z-index: 2;
  603. width: 68rpx;
  604. height: 38rpx;
  605. background: linear-gradient(90deg, #ff5854 0%, #ff2621 100%);
  606. border-radius: 10rpx 0px 10rpx 0px;
  607. font-size: 24rpx;
  608. font-weight: 500;
  609. color: #ffffff;
  610. line-height: 32rpx;
  611. }
  612. .groupon-tag {
  613. position: absolute;
  614. left: 0;
  615. top: 0;
  616. z-index: 2;
  617. width: 68rpx;
  618. height: 38rpx;
  619. background: linear-gradient(90deg, #fe832a 0%, #ff6600 100%);
  620. border-radius: 10rpx 0px 10rpx 0px;
  621. font-size: 24rpx;
  622. font-weight: 500;
  623. color: #ffffff;
  624. line-height: 32rpx;
  625. }
  626. .goods-img {
  627. width: 100%;
  628. height: 100%;
  629. background-color: #f5f5f5;
  630. }
  631. .price-unit {
  632. margin-right: -4px;
  633. }
  634. .sales-text {
  635. display: table;
  636. font-size: 24rpx;
  637. transform: scale(0.8);
  638. margin-left: 0rpx;
  639. color: #c4c4c4;
  640. }
  641. .activity-tag {
  642. font-size: 20rpx;
  643. color: #ff0000;
  644. line-height: 30rpx;
  645. padding: 0 10rpx;
  646. border: 1px solid rgba(#ff0000, 0.25);
  647. border-radius: 4px;
  648. flex-shrink: 0;
  649. }
  650. .goods-origin-price {
  651. font-size: 20rpx;
  652. color: #c4c4c4;
  653. line-height: 36rpx;
  654. text-decoration: line-through;
  655. }
  656. // xs
  657. .xs-goods-card {
  658. overflow: hidden;
  659. // max-width: 375rpx;
  660. background-color: $white;
  661. position: relative;
  662. .xs-img-box {
  663. width: 128rpx;
  664. height: 128rpx;
  665. margin-right: 20rpx;
  666. }
  667. .xs-goods-title {
  668. font-size: 26rpx;
  669. color: #333;
  670. font-weight: 500;
  671. }
  672. .xs-goods-price {
  673. font-size: 30rpx;
  674. color: $red;
  675. }
  676. }
  677. // sm
  678. .sm-goods-card {
  679. overflow: hidden;
  680. // width: 223rpx;
  681. // width: 100%;
  682. background-color: $white;
  683. position: relative;
  684. .sm-img-box {
  685. // width: 228rpx;
  686. width: 100%;
  687. height: 208rpx;
  688. }
  689. .sm-goods-content {
  690. padding: 20rpx 16rpx;
  691. box-sizing: border-box;
  692. }
  693. .sm-goods-title {
  694. font-size: 26rpx;
  695. color: #333;
  696. }
  697. .sm-goods-price {
  698. font-size: 30rpx;
  699. color: $red;
  700. }
  701. }
  702. // md
  703. .md-goods-card {
  704. overflow: hidden;
  705. width: 100%;
  706. position: relative;
  707. z-index: 1;
  708. background-color: $white;
  709. position: relative;
  710. .md-img-box {
  711. width: 100%;
  712. }
  713. .md-goods-title {
  714. font-size: 26rpx;
  715. color: #333;
  716. width: 100%;
  717. }
  718. .md-goods-subtitle {
  719. font-size: 24rpx;
  720. font-weight: 400;
  721. color: #999999;
  722. }
  723. .md-goods-price {
  724. font-size: 30rpx;
  725. color: $red;
  726. line-height: 36rpx;
  727. }
  728. .cart-box {
  729. width: 54rpx;
  730. height: 54rpx;
  731. background: linear-gradient(90deg, #fe8900, #ff5e00);
  732. border-radius: 50%;
  733. position: absolute;
  734. bottom: 50rpx;
  735. right: 20rpx;
  736. z-index: 2;
  737. .cart-icon {
  738. width: 30rpx;
  739. height: 30rpx;
  740. }
  741. }
  742. }
  743. // lg
  744. .lg-goods-card {
  745. overflow: hidden;
  746. position: relative;
  747. z-index: 1;
  748. background-color: $white;
  749. height: 280rpx;
  750. .lg-img-box {
  751. width: 280rpx;
  752. height: 280rpx;
  753. margin-right: 20rpx;
  754. }
  755. .lg-goods-title {
  756. font-size: 28rpx;
  757. font-weight: 500;
  758. color: #333333;
  759. // line-height: 36rpx;
  760. // width: 410rpx;
  761. }
  762. .lg-goods-subtitle {
  763. font-size: 24rpx;
  764. font-weight: 400;
  765. color: #999999;
  766. // line-height: 30rpx;
  767. // width: 410rpx;
  768. }
  769. .lg-goods-price {
  770. font-size: 30rpx;
  771. color: $red;
  772. line-height: 36rpx;
  773. }
  774. .buy-box {
  775. position: absolute;
  776. bottom: 20rpx;
  777. right: 20rpx;
  778. z-index: 2;
  779. width: 120rpx;
  780. height: 50rpx;
  781. background: linear-gradient(90deg, #fe8900, #ff5e00);
  782. border-radius: 25rpx;
  783. font-size: 24rpx;
  784. color: #ffffff;
  785. }
  786. .tag-box {
  787. width: 100%;
  788. }
  789. }
  790. // sl
  791. .sl-goods-card {
  792. overflow: hidden;
  793. position: relative;
  794. z-index: 1;
  795. width: 100%;
  796. background-color: $white;
  797. .sl-goods-content {
  798. padding: 20rpx 20rpx;
  799. box-sizing: border-box;
  800. }
  801. .sl-img-box {
  802. width: 100%;
  803. height: 360rpx;
  804. }
  805. .sl-goods-title {
  806. font-size: 26rpx;
  807. color: #333;
  808. font-weight: 500;
  809. }
  810. .sl-goods-subtitle {
  811. font-size: 24rpx;
  812. font-weight: 400;
  813. color: #999999;
  814. line-height: 30rpx;
  815. }
  816. .sl-goods-price {
  817. font-size: 30rpx;
  818. color: $red;
  819. line-height: 36rpx;
  820. }
  821. .buy-box {
  822. position: absolute;
  823. bottom: 20rpx;
  824. right: 20rpx;
  825. z-index: 2;
  826. width: 148rpx;
  827. height: 50rpx;
  828. background: linear-gradient(90deg, #fe8900, #ff5e00);
  829. border-radius: 25rpx;
  830. font-size: 24rpx;
  831. color: #ffffff;
  832. }
  833. }
  834. .card {
  835. width: fit-content;
  836. height: fit-content;
  837. padding: 2rpx 10rpx;
  838. background-color: red;
  839. color: #ffffff;
  840. font-size: 24rpx;
  841. margin-top: 5rpx;
  842. }
  843. .card2 {
  844. width: fit-content;
  845. height: fit-content;
  846. padding: 2rpx 10rpx;
  847. background-color: rgb(255, 242, 241);
  848. color: #ff2621;
  849. font-size: 24rpx;
  850. margin: 5rpx 0 5rpx 5rpx;
  851. }
  852. .iconBox {
  853. width: 100%;
  854. height: fit-content;
  855. margin-top: 10rpx;
  856. display: flex;
  857. justify-content: flex-start;
  858. flex-wrap: wrap;
  859. }
  860. </style>