s-goods-column.vue 29 KB

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