|
|
@ -1,302 +1,343 @@ |
|
|
|
<template> |
|
|
|
<view class="page"> |
|
|
|
<!-- 导航栏 --> |
|
|
|
<navbar title="商品详情" leftClick @leftClick="$utils.navigateBack" color="#fff" /> |
|
|
|
|
|
|
|
<uv-swiper :list="bannerList" indicator indicatorMode="dot" height="475rpx"></uv-swiper> |
|
|
|
|
|
|
|
<view class="overview"> |
|
|
|
<view class="flex sale"> |
|
|
|
<view class="flex price" :class="[role]"> |
|
|
|
<view> |
|
|
|
<text class="price-unit">¥</text> |
|
|
|
<text>{{ productDetail.price }}</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="flex tag" v-if="role"> |
|
|
|
<image class="icon" :src="vipInfo.massageVipCombo.imagePrice"></image> |
|
|
|
<text>{{ vipInfo.massageVipCombo.title }}</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
</view> |
|
|
|
<view> |
|
|
|
<text>{{ `已售出:${productDetail.sales}单` }}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="title"> |
|
|
|
<text>{{ productDetail.title }}</text> |
|
|
|
</view> |
|
|
|
<view class="flex desc"> |
|
|
|
<view v-for="tag in tags" :key="tag" class="flex tag"> |
|
|
|
<view class="dot"></view> |
|
|
|
<text>{{ tag }}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 商品详情 --> |
|
|
|
<view class="detail"> |
|
|
|
<view class="header"> |
|
|
|
<cardTitle>商品详情</cardTitle> |
|
|
|
</view> |
|
|
|
<uv-parse :content="productDetail.details"></uv-parse> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 分享和购买按钮 --> |
|
|
|
<view class="flex bar"> |
|
|
|
<button plain class="flex flex-column btn btn-share" open-type="share"> |
|
|
|
<image class="btn-share-icon" src="../static/productDetail/icon-share.png"></image> |
|
|
|
<text>分享</text> |
|
|
|
</button> |
|
|
|
<view class="flex count"> |
|
|
|
<text>合计:</text> |
|
|
|
<view class="price"> |
|
|
|
<text class="price-unit">¥</text> |
|
|
|
<!-- todo: check --> |
|
|
|
<text>{{ productDetail.price }}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<button plain class="btn btn-pay" @click="submit">立即支付</button> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="page"> |
|
|
|
<!-- 导航栏 --> |
|
|
|
<navbar title="商品详情" leftClick @leftClick="$utils.navigateBack" color="#fff" /> |
|
|
|
|
|
|
|
<uv-swiper :list="bannerList" indicator indicatorMode="dot" height="475rpx"></uv-swiper> |
|
|
|
|
|
|
|
<view class="overview"> |
|
|
|
<view class="flex sale"> |
|
|
|
<view class="flex price" :class="[role]"> |
|
|
|
<view> |
|
|
|
<text class="price-unit">¥</text> |
|
|
|
<text>{{ productDetail.price }}</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
<view class="flex tag" v-if="role"> |
|
|
|
<image class="icon" :src="vipInfo.massageVipCombo.imagePrice"></image> |
|
|
|
<text>{{ vipInfo.massageVipCombo.title }}</text> |
|
|
|
</view> |
|
|
|
|
|
|
|
</view> |
|
|
|
<view> |
|
|
|
<text>{{ `已售出:${productDetail.sales}单` }}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<view class="title"> |
|
|
|
<text>{{ productDetail.title }}</text> |
|
|
|
</view> |
|
|
|
<view class="flex desc"> |
|
|
|
<view v-for="tag in tags" :key="tag" class="flex tag"> |
|
|
|
<view class="dot"></view> |
|
|
|
<text>{{ tag }}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
|
|
|
|
|
|
|
|
<!-- 商品详情 --> |
|
|
|
<view class="detail"> |
|
|
|
<view class="header"> |
|
|
|
<cardTitle>商品详情</cardTitle> |
|
|
|
</view> |
|
|
|
<uv-parse :content="productDetail.details"></uv-parse> |
|
|
|
</view> |
|
|
|
|
|
|
|
<!-- 分享和购买按钮 --> |
|
|
|
<view class="flex bar"> |
|
|
|
<!-- #ifdef H5 --> |
|
|
|
<button plain class="flex flex-column btn btn-share" @click="handleShare"> |
|
|
|
<image class="btn-share-icon" src="../static/productDetail/icon-share.png"></image> |
|
|
|
<text>分享</text> |
|
|
|
</button> |
|
|
|
<!-- #endif --> |
|
|
|
|
|
|
|
<!-- #ifdef MP-WEIXIN --> |
|
|
|
<button plain class="flex flex-column btn btn-share" open-type="share"> |
|
|
|
<image class="btn-share-icon" src="../static/productDetail/icon-share.png"></image> |
|
|
|
<text>分享</text> |
|
|
|
</button> |
|
|
|
<!-- #endif --> |
|
|
|
|
|
|
|
<view class="flex count"> |
|
|
|
<text>合计:</text> |
|
|
|
<view class="price"> |
|
|
|
<text class="price-unit">¥</text> |
|
|
|
<!-- todo: check --> |
|
|
|
<text>{{ productDetail.price }}</text> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
<button plain class="btn btn-pay" @click="submit">立即支付</button> |
|
|
|
</view> |
|
|
|
</view> |
|
|
|
</template> |
|
|
|
|
|
|
|
<script> |
|
|
|
import { mapGetters, mapState } from 'vuex' |
|
|
|
|
|
|
|
import cardTitle from '@/components/base/cardTitle.vue' |
|
|
|
|
|
|
|
export default { |
|
|
|
components: { |
|
|
|
cardTitle, |
|
|
|
}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
productDetail: { |
|
|
|
image: '', |
|
|
|
details: '', |
|
|
|
}, |
|
|
|
id: 0, |
|
|
|
} |
|
|
|
}, |
|
|
|
computed: { |
|
|
|
...mapGetters(['role']), |
|
|
|
...mapState(['vipInfo']), |
|
|
|
// todo: check |
|
|
|
bannerList() { |
|
|
|
const { image } = this.productDetail |
|
|
|
|
|
|
|
if (!image) { |
|
|
|
return [] |
|
|
|
} |
|
|
|
|
|
|
|
return Array.isArray(image) ? image : image.split(',') |
|
|
|
}, |
|
|
|
tags() { |
|
|
|
const { tag } = this.productDetail |
|
|
|
|
|
|
|
return tag?.split('、') || [] |
|
|
|
} |
|
|
|
}, |
|
|
|
onLoad(args) { |
|
|
|
this.id = args.id |
|
|
|
|
|
|
|
this.fetchProductDetail(this.id) |
|
|
|
}, |
|
|
|
onShow() { |
|
|
|
}, |
|
|
|
import { mapGetters, mapState } from 'vuex' |
|
|
|
|
|
|
|
import cardTitle from '@/components/base/cardTitle.vue' |
|
|
|
|
|
|
|
export default { |
|
|
|
components: { |
|
|
|
cardTitle, |
|
|
|
}, |
|
|
|
data() { |
|
|
|
return { |
|
|
|
productDetail: { |
|
|
|
image: '', |
|
|
|
details: '', |
|
|
|
}, |
|
|
|
id: 0, |
|
|
|
} |
|
|
|
}, |
|
|
|
computed: { |
|
|
|
...mapGetters(['role']), |
|
|
|
...mapState(['vipInfo']), |
|
|
|
// todo: check |
|
|
|
bannerList() { |
|
|
|
const { image } = this.productDetail |
|
|
|
|
|
|
|
if (!image) { |
|
|
|
return [] |
|
|
|
} |
|
|
|
|
|
|
|
return Array.isArray(image) ? image : image.split(',') |
|
|
|
}, |
|
|
|
tags() { |
|
|
|
const { tag } = this.productDetail |
|
|
|
|
|
|
|
return tag?.split('、') || [] |
|
|
|
} |
|
|
|
}, |
|
|
|
onLoad(args) { |
|
|
|
this.id = args.id |
|
|
|
this.fetchProductDetail(this.id) |
|
|
|
|
|
|
|
// 处理分享ID参数 |
|
|
|
if (args.shareId) { |
|
|
|
uni.setStorageSync('shareId', args.shareId) |
|
|
|
} |
|
|
|
}, |
|
|
|
onShow() { |
|
|
|
// 页面显示时重新设置分享内容 |
|
|
|
this.updateShareContent() |
|
|
|
}, |
|
|
|
onShareAppMessage(res) { |
|
|
|
const { |
|
|
|
title, |
|
|
|
} = this.productDetail |
|
|
|
|
|
|
|
let o = { |
|
|
|
title: title, |
|
|
|
// todo: check |
|
|
|
imageUrl: bannerList[0], |
|
|
|
query: `id=${this.productDetail.id}`, |
|
|
|
} |
|
|
|
|
|
|
|
return o |
|
|
|
// 小程序分享:返回商品特定的分享内容 |
|
|
|
return { |
|
|
|
title: this.productDetail.title || '愈然工坊', |
|
|
|
imageUrl: this.bannerList[0] || '', |
|
|
|
path: `/pages_order/product/productDetail?id=${this.productDetail.id}${this.userInfo.id ? '&shareId=' + this.userInfo.id : ''}`, |
|
|
|
} |
|
|
|
}, |
|
|
|
methods: { |
|
|
|
// 获取商品 |
|
|
|
async fetchProductDetail(id) { |
|
|
|
try { |
|
|
|
this.productDetail = await this.$fetch('queryProductDetail', { id }) |
|
|
|
} catch (err) { |
|
|
|
|
|
|
|
} |
|
|
|
}, |
|
|
|
// 立即下单 |
|
|
|
submit() { |
|
|
|
this.$store.commit('setPayOrderProduct', [ |
|
|
|
this.productDetail |
|
|
|
]) |
|
|
|
|
|
|
|
this.$utils.navigateTo('/pages_order/order/createOrder') |
|
|
|
}, |
|
|
|
} |
|
|
|
} |
|
|
|
methods: { |
|
|
|
// #ifdef H5 |
|
|
|
// H5分享处理 |
|
|
|
handleShare() { |
|
|
|
uni.showToast({ |
|
|
|
title: '请点击右上角分享', |
|
|
|
icon: 'none' |
|
|
|
}) |
|
|
|
}, |
|
|
|
// #endif |
|
|
|
|
|
|
|
// 更新分享内容 |
|
|
|
updateShareContent() { |
|
|
|
if (this.productDetail.id) { |
|
|
|
// 设置商品特定的分享内容到全局分享配置 |
|
|
|
this.Gshare.title = this.productDetail.title || '愈然工坊' |
|
|
|
this.Gshare.desc = this.productDetail.title || '愈然工坊,温柔呵护每一刻!' |
|
|
|
this.Gshare.path = `/pages_order/product/productDetail?id=${this.productDetail.id}` |
|
|
|
this.Gshare.imageUrl = this.bannerList[0] || '' |
|
|
|
|
|
|
|
// #ifdef H5 |
|
|
|
// H5环境下重新设置微信分享 |
|
|
|
this.setupWeixinShare() |
|
|
|
// #endif |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
// 获取商品 |
|
|
|
async fetchProductDetail(id) { |
|
|
|
try { |
|
|
|
this.productDetail = await this.$fetch('queryProductDetail', { id }) |
|
|
|
|
|
|
|
// 商品数据加载完成后更新分享内容 |
|
|
|
this.updateShareContent() |
|
|
|
} catch (err) { |
|
|
|
|
|
|
|
} |
|
|
|
}, |
|
|
|
// 立即下单 |
|
|
|
submit() { |
|
|
|
this.$store.commit('setPayOrderProduct', [ |
|
|
|
this.productDetail |
|
|
|
]) |
|
|
|
|
|
|
|
this.$utils.navigateTo('/pages_order/order/createOrder') |
|
|
|
}, |
|
|
|
} |
|
|
|
} |
|
|
|
</script> |
|
|
|
|
|
|
|
<style scoped lang="scss"> |
|
|
|
$bar-height: 132rpx; |
|
|
|
|
|
|
|
.page { |
|
|
|
padding-bottom: calc(#{$bar-height} + env(safe-area-inset-bottom)); |
|
|
|
|
|
|
|
background-color: #F3F3F3; |
|
|
|
|
|
|
|
/deep/ .nav-bar__view { |
|
|
|
background-image: linear-gradient(#84A73F, #D8FF8F); |
|
|
|
} |
|
|
|
|
|
|
|
.overview { |
|
|
|
padding: 16rpx 31rpx 18rpx 24rpx; |
|
|
|
background-color: $uni-fg-color; |
|
|
|
|
|
|
|
.sale { |
|
|
|
justify-content: space-between; |
|
|
|
color: #949494; |
|
|
|
font-size: 20rpx; |
|
|
|
|
|
|
|
.price { |
|
|
|
color: #FF2A2A; |
|
|
|
font-size: 45rpx; |
|
|
|
|
|
|
|
&-unit { |
|
|
|
font-size: 30rpx; |
|
|
|
margin-right: 3rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.tag { |
|
|
|
font-size: 18rpx; |
|
|
|
font-weight: 700; |
|
|
|
padding: 9rpx 12rpx 9rpx 19rpx; |
|
|
|
margin-left: 15rpx; |
|
|
|
|
|
|
|
.icon { |
|
|
|
width: 27rpx; |
|
|
|
height: 19rpx; |
|
|
|
margin-right: 3rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.member-personal { |
|
|
|
color: $uni-color-light; |
|
|
|
.tag { |
|
|
|
background-color: rgba($color: #D8FF8F, $alpha: 0.72); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.member-business { |
|
|
|
color: #FFB465; |
|
|
|
.tag { |
|
|
|
background-color: rgba($color: #FFFBC4, $alpha: 0.72); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.title { |
|
|
|
color: #3A3A3A; |
|
|
|
font-size: 28rpx; |
|
|
|
font-weight: 700; |
|
|
|
margin-top: 15rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.desc { |
|
|
|
justify-content: space-between; |
|
|
|
margin-top: 20rpx; |
|
|
|
|
|
|
|
.tag { |
|
|
|
color: #949494; |
|
|
|
font-size: 22rpx; |
|
|
|
|
|
|
|
.dot { |
|
|
|
width: 8rpx; |
|
|
|
height: 8rpx; |
|
|
|
border-radius: 50%; |
|
|
|
background-color: #949494; |
|
|
|
margin-right: 16rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.detail { |
|
|
|
margin-top: 12rpx; |
|
|
|
padding: 18rpx 28rpx; |
|
|
|
background-color: $uni-fg-color; |
|
|
|
|
|
|
|
.header { |
|
|
|
margin-bottom: 30rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.bar { |
|
|
|
position: fixed; |
|
|
|
bottom: 0; |
|
|
|
left: 0; |
|
|
|
width: 100vw; |
|
|
|
height: $bar-height; |
|
|
|
padding-bottom: env(safe-area-inset-bottom); |
|
|
|
background-color: $uni-fg-color; |
|
|
|
|
|
|
|
.count { |
|
|
|
flex: 1; |
|
|
|
color: #000000; |
|
|
|
font-size: 28rpx; |
|
|
|
margin-left: 29rpx; |
|
|
|
padding-left: 40rpx; |
|
|
|
border-left: 1rpx solid #B3997E; |
|
|
|
|
|
|
|
justify-content: flex-start; |
|
|
|
|
|
|
|
.price { |
|
|
|
color: #FF2A2A; |
|
|
|
font-size: 30rpx; |
|
|
|
|
|
|
|
&-unit { |
|
|
|
font-size: 18rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.btn { |
|
|
|
border: none; |
|
|
|
line-height: 1; |
|
|
|
background-color: transparent; |
|
|
|
padding: 0; |
|
|
|
width: auto; |
|
|
|
height: auto; |
|
|
|
margin: 0; |
|
|
|
|
|
|
|
&-share { |
|
|
|
margin-left: 58rpx; |
|
|
|
color: #000000; |
|
|
|
font-size: 22rpx; |
|
|
|
|
|
|
|
&-icon { |
|
|
|
width: 48rpx; |
|
|
|
height: 50rpx; |
|
|
|
margin-bottom: 11rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&-pay { |
|
|
|
margin-right: 27rpx; |
|
|
|
padding: 24rpx 137rpx; |
|
|
|
color: $uni-text-color-inverse; |
|
|
|
font-size: 28rpx; |
|
|
|
border-radius: 44rpx; |
|
|
|
background-image: linear-gradient(to right, #84A73F, #D8FF8F); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
$bar-height: 132rpx; |
|
|
|
|
|
|
|
.page { |
|
|
|
padding-bottom: calc(#{$bar-height} + env(safe-area-inset-bottom)); |
|
|
|
|
|
|
|
background-color: #F3F3F3; |
|
|
|
|
|
|
|
/deep/ .nav-bar__view { |
|
|
|
background-image: linear-gradient(#84A73F, #D8FF8F); |
|
|
|
} |
|
|
|
|
|
|
|
.overview { |
|
|
|
padding: 16rpx 31rpx 18rpx 24rpx; |
|
|
|
background-color: $uni-fg-color; |
|
|
|
|
|
|
|
.sale { |
|
|
|
justify-content: space-between; |
|
|
|
color: #949494; |
|
|
|
font-size: 20rpx; |
|
|
|
|
|
|
|
.price { |
|
|
|
color: #FF2A2A; |
|
|
|
font-size: 45rpx; |
|
|
|
|
|
|
|
&-unit { |
|
|
|
font-size: 30rpx; |
|
|
|
margin-right: 3rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.tag { |
|
|
|
font-size: 18rpx; |
|
|
|
font-weight: 700; |
|
|
|
padding: 9rpx 12rpx 9rpx 19rpx; |
|
|
|
margin-left: 15rpx; |
|
|
|
|
|
|
|
.icon { |
|
|
|
width: 27rpx; |
|
|
|
height: 19rpx; |
|
|
|
margin-right: 3rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.member-personal { |
|
|
|
color: $uni-color-light; |
|
|
|
|
|
|
|
.tag { |
|
|
|
background-color: rgba($color: #D8FF8F, $alpha: 0.72); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&.member-business { |
|
|
|
color: #FFB465; |
|
|
|
|
|
|
|
.tag { |
|
|
|
background-color: rgba($color: #FFFBC4, $alpha: 0.72); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.title { |
|
|
|
color: #3A3A3A; |
|
|
|
font-size: 28rpx; |
|
|
|
font-weight: 700; |
|
|
|
margin-top: 15rpx; |
|
|
|
} |
|
|
|
|
|
|
|
.desc { |
|
|
|
justify-content: space-between; |
|
|
|
margin-top: 20rpx; |
|
|
|
|
|
|
|
.tag { |
|
|
|
color: #949494; |
|
|
|
font-size: 22rpx; |
|
|
|
|
|
|
|
.dot { |
|
|
|
width: 8rpx; |
|
|
|
height: 8rpx; |
|
|
|
border-radius: 50%; |
|
|
|
background-color: #949494; |
|
|
|
margin-right: 16rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.detail { |
|
|
|
margin-top: 12rpx; |
|
|
|
padding: 18rpx 28rpx; |
|
|
|
background-color: $uni-fg-color; |
|
|
|
|
|
|
|
.header { |
|
|
|
margin-bottom: 30rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.bar { |
|
|
|
position: fixed; |
|
|
|
bottom: 0; |
|
|
|
left: 0; |
|
|
|
width: 100vw; |
|
|
|
height: $bar-height; |
|
|
|
padding-bottom: env(safe-area-inset-bottom); |
|
|
|
background-color: $uni-fg-color; |
|
|
|
|
|
|
|
.count { |
|
|
|
flex: 1; |
|
|
|
color: #000000; |
|
|
|
font-size: 28rpx; |
|
|
|
margin-left: 29rpx; |
|
|
|
padding-left: 40rpx; |
|
|
|
border-left: 1rpx solid #B3997E; |
|
|
|
|
|
|
|
justify-content: flex-start; |
|
|
|
|
|
|
|
.price { |
|
|
|
color: #FF2A2A; |
|
|
|
font-size: 30rpx; |
|
|
|
|
|
|
|
&-unit { |
|
|
|
font-size: 18rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
.btn { |
|
|
|
border: none; |
|
|
|
line-height: 1; |
|
|
|
background-color: transparent; |
|
|
|
padding: 0; |
|
|
|
width: auto; |
|
|
|
height: auto; |
|
|
|
margin: 0; |
|
|
|
|
|
|
|
&-share { |
|
|
|
margin-left: 58rpx; |
|
|
|
color: #000000; |
|
|
|
font-size: 22rpx; |
|
|
|
|
|
|
|
&-icon { |
|
|
|
width: 48rpx; |
|
|
|
height: 50rpx; |
|
|
|
margin-bottom: 11rpx; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
&-pay { |
|
|
|
margin-right: 27rpx; |
|
|
|
padding: 24rpx 137rpx; |
|
|
|
color: $uni-text-color-inverse; |
|
|
|
font-size: 28rpx; |
|
|
|
border-radius: 44rpx; |
|
|
|
background-image: linear-gradient(to right, #84A73F, #D8FF8F); |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
</style> |