|
|
- <template>
- <view :class="['product', size]"
- @touchstart="onTouchstart"
- @touchmove="onTouchmove"
- @touchend="onTouchend"
- >
- <image class="product-img" :src="data.image" mode="aspectFill"></image>
- <view class="flex flex-column product-info">
- <view class="product-info-top">
- <view class="product-name text-ellipsis-2">{{ data.title }}</view>
- <view class="product-desc text-ellipsis" v-if="tagDesc">{{ tagDesc }}</view>
- </view>
- <view class="flex product-info-bottom">
- <view class="product-detail">
- <view class="flex product-price">
- <view class="product-price-val">
- <text>¥</text>
- <text class="highlight">{{ priceInt }}</text>
- <text>{{ `${priceFrac}起` }}</text>
- </view>
- <view class="product-price-bef" v-if="data.priceOrigin">
- {{ `¥${data.priceOrigin}` }}
- </view>
- </view>
- <view class="product-registered">
- {{ `${data.applyNum}人已报名` }}
- </view>
- </view>
- <button class="btn" @click="onRegistrate">报名</button>
- </view>
- </view>
-
- <button class="flex btn btn-collect"
- :style="collectBtnStyle"
- @click.stop="onCollect"
- @touchstart.stop="onCollect"
- >
- <view>{{ isCollected ? '移除收藏' : '收藏' }}</view>
- </button>
- </view>
- </template>
-
- <script>
- export default {
- props: {
- data: {
- type: Object,
- default() {
- return {}
- }
- },
- // todo: fetch
- isCollected: {
- type: Boolean,
- default: false,
- },
- size: {
- type: String,
- default: 'normal' // normal | small
- }
- },
- data() {
- return {
- isMove: false,
- startClientX: null,
- displayX: 0,
- }
- },
- computed: {
- tagDesc() {
- // todo: check key
- const { tagList } = this.data
-
- return tagList?.length ? tagList.split('、').join('·') : ''
- return
- const { categoryId_dictText, timeId_dictText, ageId_dictText } = this.data
-
- return [categoryId_dictText, timeId_dictText, ageId_dictText].filter(val => val).join('·')
- },
- priceInt() {
- return Math.floor(this.data.priceDiscount)
- },
- priceFrac() {
- let frac = this.data.priceDiscount % this.priceInt
- return frac > 0 ? frac.toFixed(2).slice(1) : ''
- },
- collectBtnWidth() {
- return this.isCollected ? 80 : 56
- },
- collectBtnStyle() {
- const width = this.collectBtnWidth
- const background = this.isCollected ? '#26334E' : '#FF9035'
-
- let display = Math.ceil(this.displayX / width * 100)
-
- display > 100 && (display = 100)
-
- const translateX = 100 - display
-
- return `width: ${width}px; transform: translateX(${translateX}%); background: ${background};`
- }
- },
- methods: {
- onTouchstart(e) {
- const clientX = e.changedTouches[0].clientX
-
- this.isMove = false
- this.startClientX = clientX
- this.displayX = 0
- },
- onTouchmove(e) {
- const clientX = e.changedTouches[0].clientX
-
- if (clientX < this.startClientX) {
- this.displayX = this.startClientX - clientX
- } else {
- this.displayX = 0
- }
-
- this.isMove = true
- },
- onTouchend() {
- console.log('displayX', this.displayX, this.collectBtnWidth, this.displayX < this.collectBtnWidth)
- if (this.displayX < this.collectBtnWidth) {
- this.displayX = 0
- }
-
- this.isMove = false
- },
- showCollectBtn() {
- this.displayX = 100
- },
- hiddenCollectBtn() {
- this.displayX = 0
- },
- async onCollect() {
- console.log('onCollect')
-
-
- try {
-
- let succ
-
- if (this.isCollected) {
- // todo: fetch cancel collect
- succ = true
- uni.showToast({
- icon: 'success',
- title: '已移除收藏',
- });
- } else {
- succ = await this.$store.dispatch('collect', this.data.id)
- }
- succ && this.hiddenCollectBtn()
-
- this.$emit('collect', !this.isCollected)
- } catch (err) {
- console.log('collect err', err)
- }
-
- },
- onRegistrate() {
- this.$utils.navigateTo(`/pages_order/product/productDetail?id=${this.data.id}`)
- },
- },
- }
- </script>
-
- <style scoped lang="scss">
- .product {
- position: relative;
- height: 464rpx;
- background: #FFFFFF;
- border: 2rpx solid #FFFFFF;
- border-radius: 32rpx;
- overflow: hidden;
- font-size: 0;
-
- &-img {
- width: 100%;
- height: 220rpx;
- }
-
- &-info {
- height: 244rpx;
- padding: 16rpx 16rpx 24rpx 16rpx;
- box-sizing: border-box;
- justify-content: space-between;
-
- &-top {
- width: 100%;
- }
-
- &-bottom {
- width: 100%;
- justify-content: space-between;
- }
-
- }
-
- &-name {
- font-size: 28rpx;
- font-weight: 500;
- color: #000000;
- }
-
- &-desc {
- margin-top: 8rpx;
- font-size: 24rpx;
- color: #8B8B8B;
- }
-
- &-detail {
-
- }
-
- &-price {
- justify-content: flex-start;
- align-items: baseline;
- column-gap: 12rpx;
-
- &-val {
- font-size: 24rpx;
- font-weight: 500;
- color: #FF4800;
-
- .highlight {
- font-size: 32rpx;
- }
-
- }
-
- &-bef {
- text-decoration: line-through;
- font-size: 24rpx;
- color: #8B8B8B;
- }
- }
-
- &-registered {
- font-size: 24rpx;
- color: #8B8B8B;
- }
-
- .btn {
- padding: 11rpx 32rpx;
- font-size: 26rpx;
- font-weight: 500;
- color: #FFFFFF;
- background: #00A9FF;
- border-radius: 24rpx;
- }
-
- &.small {
- .btn {
- padding: 11rpx 16rpx;
- }
- }
-
- }
-
- .btn.btn-collect {
- position: absolute;
- top: 0;
- right: 0;
- row-gap: 8rpx;
- // width: 112rpx;
- height: 100%;
- font-size: 24rpx;
- line-height: 1;
- color: #FFFFFF;
- // background: #FF9035;
- border-radius: 0;
- }
-
- </style>
|