鸿宇研学生前端代码
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.

269 lines
5.8 KiB

2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
2 months ago
  1. <template>
  2. <view :class="['product', size]"
  3. @touchstart="onTouchstart"
  4. @touchmove="onTouchmove"
  5. @touchend="onTouchend"
  6. >
  7. <image class="product-img" :src="data.image" mode="aspectFill"></image>
  8. <view class="flex flex-column product-info">
  9. <view class="product-info-top">
  10. <view class="product-name text-ellipsis-2">{{ data.title }}</view>
  11. <view class="product-desc text-ellipsis" v-if="tagDesc">{{ tagDesc }}</view>
  12. </view>
  13. <view class="flex product-info-bottom">
  14. <view class="product-detail">
  15. <view class="flex product-price">
  16. <view class="product-price-val">
  17. <text>¥</text>
  18. <text class="highlight">{{ priceInt }}</text>
  19. <text>{{ `${priceFrac}` }}</text>
  20. </view>
  21. <view class="product-price-bef" v-if="data.priceOrigin">
  22. {{ `¥${data.priceOrigin}` }}
  23. </view>
  24. </view>
  25. <view class="product-registered">
  26. {{ `${data.applyNum}人已报名` }}
  27. </view>
  28. </view>
  29. <button class="btn" @click="onRegistrate">报名</button>
  30. </view>
  31. </view>
  32. <button class="flex btn btn-collect"
  33. :style="collectBtnStyle"
  34. @click.stop="onCollect"
  35. @touchstart.stop="onCollect"
  36. >
  37. <view>{{ isCollected ? '移除收藏' : '收藏' }}</view>
  38. </button>
  39. </view>
  40. </template>
  41. <script>
  42. export default {
  43. props: {
  44. data: {
  45. type: Object,
  46. default() {
  47. return {}
  48. }
  49. },
  50. size: {
  51. type: String,
  52. default: 'normal' // normal | small
  53. }
  54. },
  55. data() {
  56. return {
  57. isMove: false,
  58. startClientX: null,
  59. displayX: 0,
  60. collectBtnVisible: false,
  61. }
  62. },
  63. computed: {
  64. tagDesc() {
  65. const { tagList } = this.data
  66. return tagList?.length ? tagList.split('、').join('·') : ''
  67. },
  68. priceInt() {
  69. return Math.floor(this.data.priceDiscount)
  70. },
  71. priceFrac() {
  72. let frac = this.data.priceDiscount % this.priceInt
  73. return frac > 0 ? frac.toFixed(2).slice(1) : ''
  74. },
  75. isCollected() {
  76. return this.data.isCollection == '1'
  77. },
  78. collectBtnWidth() {
  79. return this.isCollected ? 80 : 56
  80. },
  81. collectBtnStyle() {
  82. const width = this.collectBtnWidth
  83. const background = this.isCollected ? '#26334E' : '#FF9035'
  84. let display = Math.ceil(this.displayX / width * 100)
  85. display > 100 && (display = 100)
  86. const translateX = 100 - display
  87. return `width: ${width}px; transform: translateX(${translateX}%); background: ${background};`
  88. },
  89. },
  90. methods: {
  91. onTouchstart(e) {
  92. const clientX = e.changedTouches[0].clientX
  93. this.isMove = false
  94. this.startClientX = clientX
  95. this.displayX = 0
  96. },
  97. onTouchmove(e) {
  98. const clientX = e.changedTouches[0].clientX
  99. if (clientX < this.startClientX) {
  100. this.displayX = this.startClientX - clientX
  101. } else {
  102. this.displayX = 0
  103. }
  104. this.isMove = true
  105. },
  106. onTouchend() {
  107. if (!this.isMove && !this.collectBtnVisible) {
  108. this.onRegistrate()
  109. }
  110. if (this.displayX < this.collectBtnWidth) {
  111. this.displayX = 0
  112. }
  113. if (this.displayX) {
  114. this.collectBtnVisible = true
  115. } else {
  116. this.collectBtnVisible = false
  117. }
  118. this.isMove = false
  119. },
  120. showCollectBtn() {
  121. this.displayX = 100
  122. },
  123. hiddenCollectBtn() {
  124. this.displayX = 0
  125. },
  126. async onCollect() {
  127. try {
  128. let succ = await this.$store.dispatch('collect', this.data.id)
  129. succ && this.hiddenCollectBtn()
  130. this.$emit('collect', !this.isCollected)
  131. } catch (err) {
  132. console.log('collect err', err)
  133. }
  134. },
  135. onRegistrate() {
  136. this.$utils.navigateTo(`/pages_order/product/productDetail?id=${this.data.id}`)
  137. },
  138. },
  139. }
  140. </script>
  141. <style scoped lang="scss">
  142. .product {
  143. position: relative;
  144. height: 464rpx;
  145. background: #FFFFFF;
  146. border: 2rpx solid #FFFFFF;
  147. border-radius: 32rpx;
  148. overflow: hidden;
  149. font-size: 0;
  150. &-img {
  151. width: 100%;
  152. height: 220rpx;
  153. }
  154. &-info {
  155. height: 244rpx;
  156. padding: 16rpx 16rpx 24rpx 16rpx;
  157. box-sizing: border-box;
  158. justify-content: space-between;
  159. &-top {
  160. width: 100%;
  161. }
  162. &-bottom {
  163. width: 100%;
  164. justify-content: space-between;
  165. }
  166. }
  167. &-name {
  168. font-size: 28rpx;
  169. font-weight: 500;
  170. color: #000000;
  171. }
  172. &-desc {
  173. margin-top: 8rpx;
  174. font-size: 24rpx;
  175. color: #8B8B8B;
  176. }
  177. &-detail {
  178. }
  179. &-price {
  180. justify-content: flex-start;
  181. align-items: baseline;
  182. column-gap: 12rpx;
  183. flex-wrap: wrap;
  184. &-val {
  185. font-size: 24rpx;
  186. font-weight: 500;
  187. color: #FF4800;
  188. white-space: nowrap;
  189. .highlight {
  190. font-size: 32rpx;
  191. }
  192. }
  193. &-bef {
  194. text-decoration: line-through;
  195. font-size: 24rpx;
  196. color: #8B8B8B;
  197. }
  198. }
  199. &-registered {
  200. font-size: 24rpx;
  201. color: #8B8B8B;
  202. }
  203. .btn {
  204. padding: 11rpx 32rpx;
  205. font-size: 26rpx;
  206. font-weight: 500;
  207. color: #FFFFFF;
  208. background: #00A9FF;
  209. border-radius: 24rpx;
  210. white-space: nowrap;
  211. }
  212. &.small {
  213. .btn {
  214. padding: 11rpx 16rpx;
  215. }
  216. }
  217. }
  218. .btn.btn-collect {
  219. position: absolute;
  220. top: 0;
  221. right: 0;
  222. row-gap: 8rpx;
  223. // width: 112rpx;
  224. height: 100%;
  225. font-size: 24rpx;
  226. line-height: 1;
  227. color: #FFFFFF;
  228. // background: #FF9035;
  229. border-radius: 0;
  230. }
  231. </style>