goods-receive-buy-popup.vue 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. <template>
  2. <view class="goods-receive-buy-pupup" v-if="productData">
  3. <uni-popup ref="popup" type="bottom">
  4. <view class="close iconfont icon-iconfontguanbi" @click="close"></view>
  5. <view class="popup-content" :style="{ paddingBottom: safeArea ? 0 : '40rpx' }">
  6. <view class="content">
  7. <!-- 商品信息 -->
  8. <view class="info">
  9. <image :src="productData.mainImage" class="cover"></image>
  10. <view class="price">
  11. <!-- 单价 -->
  12. <view class="row">
  13. <view class="label">单价:</view>
  14. <!-- 拼团价 -->
  15. <template v-if="productData.activityType === 'group'">
  16. <view class="amount" v-if="groupBuyFlag">{{ productPrice | priceFormat }}</view>
  17. <view class="amount" v-else>{{ productData.normalPrice | priceFormat }}</view>
  18. </template>
  19. <!-- 其它价格 -->
  20. <template v-else>
  21. <view class="amount">{{ productPrice | priceFormat }}</view>
  22. </template>
  23. </view>
  24. <view class="row tags">
  25. <!-- 券后价 -->
  26. <template v-if="hasCouponPrice && priceType === 'normal'">
  27. <view class="tag-qh">券后价¥{{ productData.couponPrice | priceFormat }}</view>
  28. </template>
  29. <!-- 价格标签 -->
  30. <template v-if="priceType !== 'normal'">
  31. <view class="tag-pt" v-if="priceType === 'group'">
  32. <text v-if="collageInfo">{{ collageInfo.memberNum }}人拼团</text>
  33. </view>
  34. <template v-else-if="priceType === 'activity'">
  35. <view class="tag-hd">活动价</view>
  36. <view class="clickable" @click="$emit('detail')">查看活动价</view>
  37. </template>
  38. <view class="tag-xs" v-else>限时特价</view>
  39. </template>
  40. </view>
  41. </view>
  42. </view>
  43. <!-- 规格 -->
  44. <view class="unit">
  45. <view class="label">规格:</view>
  46. <view class="list">
  47. <view class="item">3ml</view>
  48. <view class="item">135ml + 小样20ml</view>
  49. <view class="item">3ml 2瓶</view>
  50. <view class="item">10ml 2瓶</view>
  51. <view class="item disabled">10ml 2瓶</view>
  52. <view class="item">135ml + 精华20ml</view>
  53. <view class="item active">5ml 2瓶</view>
  54. </view>
  55. </view>
  56. <!-- 购买数量 -->
  57. <view class="count">
  58. <view class="label">购买数量:</view>
  59. <cm-number-box v-model.lazy="count" :max="limitedNum"></cm-number-box>
  60. </view>
  61. </view>
  62. <!-- 优惠券使用提示 -->
  63. <view class="tip">
  64. <template v-if="productData.couponStatus > 0 && productData.couponId">
  65. 当前商品可使用
  66. <text v-text="couponTip"></text>
  67. 优惠券
  68. </template>
  69. </view>
  70. <tui-button type="base" width="600rpx" height="90rpx" shape="circle" @click="$emit('submit', count)">
  71. <template v-if="navbarType === 'buy'">
  72. <text v-if="productData.couponStatus === 1 && productData.couponId">领券购买</text>
  73. <text v-else>立即购买</text>
  74. </template>
  75. <text v-else>确认</text>
  76. </tui-button>
  77. </view>
  78. </uni-popup>
  79. </view>
  80. </template>
  81. <script>
  82. import { mapGetters } from 'vuex'
  83. export default {
  84. name: 'goods-receive-buy-pupup',
  85. props: {
  86. productData: {
  87. type: Object,
  88. default: () => null
  89. },
  90. couponTip: {
  91. type: String,
  92. default: ''
  93. },
  94. navbarType: {
  95. type: String,
  96. default: 'buy'
  97. },
  98. groupBuyFlag: {
  99. type: Boolean,
  100. default: true
  101. }
  102. },
  103. data() {
  104. return {
  105. count: 1
  106. }
  107. },
  108. computed: {
  109. ...mapGetters(['safeArea']),
  110. productPrice() {
  111. return this.generatePrice()
  112. },
  113. limitedNum() {
  114. if (this.productData.collageStatus > 0) {
  115. return this.productData.collageProduct.limitedNum || this.productData.stock
  116. }
  117. return this.productData.stock
  118. },
  119. /* 商品价格类型 normal: 普通价 | group: 拼团价 | activity: 活动价 | time-limit: 限时特价 | coupon: 券后价 */
  120. priceType() {
  121. return this.productData?.activityType
  122. },
  123. // 有可使用优惠券
  124. hasCouponPrice() {
  125. return this.productData.couponStatus === 1
  126. },
  127. // 商品拼团信息
  128. collageInfo() {
  129. return this.productData?.collageProduct
  130. }
  131. },
  132. methods: {
  133. onNumberChange(num) {
  134. this.count = num
  135. },
  136. open() {
  137. this.$refs.popup.open()
  138. this.$emit('open')
  139. this.count = 1
  140. },
  141. close() {
  142. this.$refs.popup.close()
  143. this.$emit('close')
  144. this.count = 1
  145. },
  146. generatePrice() {
  147. // 非阶梯价
  148. if (this.productData.activeStatus <= 0) {
  149. return this.productData.price
  150. }
  151. // 阶梯价列表为空
  152. if (!this.productData.ladderList) {
  153. return this.productData.price
  154. }
  155. // 阶梯价
  156. const lastItem = this.productData.ladderList
  157. .sort((a, b) => b.buyNum - a.buyNum)
  158. .find(item => this.count >= item.buyNum)
  159. return lastItem ? lastItem.buyPrice : this.productData.price
  160. }
  161. }
  162. }
  163. </script>
  164. <style>
  165. .vue-ref {
  166. border-radius: 16rpx 16rpx 0 0;
  167. overflow: hidden;
  168. }
  169. </style>
  170. <style lang="scss" scoped>
  171. .goods-receive-buy-pupup {
  172. position: relative;
  173. .close {
  174. position: absolute;
  175. right: 24rpx;
  176. top: 24rpx;
  177. color: #999;
  178. font-size: 32rpx;
  179. }
  180. .popup-content {
  181. @extend .cm-flex-center;
  182. flex-direction: column;
  183. padding: 40rpx 32rpx;
  184. background-color: #fff;
  185. border-radius: 16rpx 16rpx 0 0;
  186. &::after {
  187. position: absolute;
  188. content: '';
  189. width: 100%;
  190. height: 80rpx;
  191. bottom: -80rpx;
  192. left: 0;
  193. background-color: #fff;
  194. }
  195. .content {
  196. width: 100%;
  197. .unit,
  198. .count {
  199. .label {
  200. font-weight: bold;
  201. color: #333333;
  202. font-size: 28rpx;
  203. }
  204. }
  205. .count {
  206. @extend .cm-flex-between;
  207. align-items: center;
  208. margin-top: 68rpx;
  209. }
  210. .unit {
  211. margin-top: 32rpx;
  212. .list {
  213. display: flex;
  214. flex-wrap: wrap;
  215. .item {
  216. position: relative;
  217. height: 48rpx;
  218. line-height: 46rpx;
  219. padding: 0 28rpx;
  220. background: #f5f5f5;
  221. color: #666666;
  222. font-size: 24rpx;
  223. box-sizing: border-box;
  224. border: 1rpx solid #f5f5f5;
  225. margin-right: 16rpx;
  226. margin-top: 24rpx;
  227. border-radius: 24rpx;
  228. &.active {
  229. color: #ff457b;
  230. border-color: #ff457b;
  231. background: #fff8fd;
  232. }
  233. &.disabled {
  234. // border: 1rpx solid #f9f9f9;
  235. // background: #f9f9f9;
  236. // color: #ddd;
  237. &::after {
  238. content: '缺货';
  239. position: absolute;
  240. height: 32rpx;
  241. line-height: 32rpx;
  242. background: #cccccc;
  243. color: #fff;
  244. padding: 0 10rpx;
  245. right: 0;
  246. top: 0;
  247. transform: translate(30%, -50%);
  248. font-size: 22rpx;
  249. border-radius: 17rpx;
  250. border: 2rpx solid #fff;
  251. }
  252. }
  253. }
  254. }
  255. }
  256. .info {
  257. display: flex;
  258. .cover {
  259. width: 180rpx;
  260. height: 180rpx;
  261. border: 1px solid #e1e1e1;
  262. }
  263. .price {
  264. margin-left: 24rpx;
  265. margin-top: 24rpx;
  266. .label {
  267. font-size: 24rpx;
  268. color: #666666;
  269. }
  270. .amount {
  271. font-size: 26rpx;
  272. color: #ff457b;
  273. font-weight: bold;
  274. &::before {
  275. content: '¥';
  276. }
  277. }
  278. .row {
  279. display: flex;
  280. align-items: center;
  281. &:nth-child(2) {
  282. margin-top: 24rpx;
  283. }
  284. }
  285. }
  286. .tags {
  287. & > view {
  288. margin-right: 24rpx;
  289. &:last-child {
  290. margin-right: 0;
  291. }
  292. }
  293. .clickable {
  294. font-size: 22rpx;
  295. color: #ff457b;
  296. }
  297. .tag-qh {
  298. display: inline-block;
  299. line-height: 40rpx;
  300. height: 40rpx;
  301. margin-top: 14rpx;
  302. background: #ff457b;
  303. border-radius: 25rpx;
  304. padding: 0 15rpx;
  305. font-size: 24rpx;
  306. font-weight: bold;
  307. color: #ffffff;
  308. }
  309. .tag-pt {
  310. @extend .cm-flex-center;
  311. height: 32rpx;
  312. padding: 0 8rpx;
  313. background: linear-gradient(90deg, #6431f2 0%, #b03bb8 49%, #ff457b 100%);
  314. border-radius: 4rpx;
  315. font-size: 22rpx;
  316. color: #fff;
  317. }
  318. .tag-hd,
  319. .tag-xs {
  320. @extend .cm-flex-center;
  321. display: block;
  322. height: 30rpx;
  323. padding: 0 8rpx;
  324. background: #fff3f7;
  325. border: 1rpx solid #ff457b;
  326. border-radius: 4rpx;
  327. font-size: 22rpx;
  328. color: #ff457b;
  329. }
  330. }
  331. }
  332. }
  333. .tip {
  334. margin: 70rpx 0 24rpx;
  335. font-size: 24rpx;
  336. color: #666;
  337. text {
  338. color: #ff457b;
  339. }
  340. }
  341. }
  342. }
  343. </style>