推拿小程序前端代码仓库
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.

342 lines
9.4 KiB

4 months ago
4 months ago
4 months ago
4 months ago
  1. <template>
  2. <view class="page">
  3. <!-- 导航栏 -->
  4. <navbar title="商品详情" leftClick @leftClick="$utils.navigateBack" color="#fff" />
  5. <uv-swiper :list="bannerList" indicator indicatorMode="dot" height="475rpx"></uv-swiper>
  6. <view class="overview">
  7. <view class="flex sale">
  8. <view class="flex price" :class="[role]">
  9. <view>
  10. <text class="price-unit"></text>
  11. <text>{{ productDetail.price }}</text>
  12. </view>
  13. <view class="flex tag" v-if="role">
  14. <image class="icon" :src="vipInfo.massageVipCombo.imagePrice"></image>
  15. <text>{{ vipInfo.massageVipCombo.title }}</text>
  16. </view>
  17. </view>
  18. <view>
  19. <text>{{ `已售出:${productDetail.sales}` }}</text>
  20. </view>
  21. </view>
  22. <view class="title">
  23. <text>{{ productDetail.title }}</text>
  24. </view>
  25. <view class="flex desc">
  26. <view v-for="tag in tags" :key="tag" class="flex tag">
  27. <view class="dot"></view>
  28. <text>{{ tag }}</text>
  29. </view>
  30. </view>
  31. </view>
  32. <!-- 商品详情 -->
  33. <view class="detail">
  34. <view class="header">
  35. <cardTitle>商品详情</cardTitle>
  36. </view>
  37. <uv-parse :content="productDetail.details"></uv-parse>
  38. </view>
  39. <!-- 分享和购买按钮 -->
  40. <view class="flex bar">
  41. <!-- #ifdef H5 -->
  42. <button plain class="flex flex-column btn btn-share" @click="handleShare">
  43. <image class="btn-share-icon" src="../static/productDetail/icon-share.png"></image>
  44. <text>分享</text>
  45. </button>
  46. <!-- #endif -->
  47. <!-- #ifdef MP-WEIXIN -->
  48. <button plain class="flex flex-column btn btn-share" open-type="share">
  49. <image class="btn-share-icon" src="../static/productDetail/icon-share.png"></image>
  50. <text>分享</text>
  51. </button>
  52. <!-- #endif -->
  53. <view class="flex count">
  54. <text>合计</text>
  55. <view class="price">
  56. <text class="price-unit">¥</text>
  57. <!-- todo: check -->
  58. <text>{{ productDetail.price }}</text>
  59. </view>
  60. </view>
  61. <button plain class="btn btn-pay" @click="submit">立即支付</button>
  62. </view>
  63. </view>
  64. </template>
  65. <script>
  66. import { mapGetters, mapState } from 'vuex'
  67. import cardTitle from '@/components/base/cardTitle.vue'
  68. export default {
  69. components: {
  70. cardTitle,
  71. },
  72. data() {
  73. return {
  74. productDetail: {
  75. image: '',
  76. details: '',
  77. },
  78. id: 0,
  79. }
  80. },
  81. computed: {
  82. ...mapGetters(['role']),
  83. ...mapState(['vipInfo']),
  84. // todo: check
  85. bannerList() {
  86. const { image } = this.productDetail
  87. if (!image) {
  88. return []
  89. }
  90. return Array.isArray(image) ? image : image.split(',')
  91. },
  92. tags() {
  93. const { tag } = this.productDetail
  94. return tag?.split('、') || []
  95. }
  96. },
  97. onLoad(args) {
  98. this.id = args.id
  99. this.fetchProductDetail(this.id)
  100. // 处理分享ID参数
  101. if (args.shareId) {
  102. uni.setStorageSync('shareId', args.shareId)
  103. }
  104. },
  105. onShow() {
  106. // 页面显示时重新设置分享内容
  107. this.updateShareContent()
  108. },
  109. onShareAppMessage(res) {
  110. // 小程序分享:返回商品特定的分享内容
  111. return {
  112. title: this.productDetail.title || '愈然工坊',
  113. imageUrl: this.bannerList[0] || '',
  114. path: `/pages_order/product/productDetail?id=${this.productDetail.id}${this.userInfo.id ? '&shareId=' + this.userInfo.id : ''}`,
  115. }
  116. },
  117. methods: {
  118. // #ifdef H5
  119. // H5分享处理
  120. handleShare() {
  121. uni.showToast({
  122. title: '请点击右上角分享',
  123. icon: 'none'
  124. })
  125. },
  126. // #endif
  127. // 更新分享内容
  128. updateShareContent() {
  129. if (this.productDetail.id) {
  130. // 设置商品特定的分享内容到全局分享配置
  131. this.Gshare.title = this.productDetail.title || '愈然工坊'
  132. this.Gshare.desc = this.productDetail.title || '愈然工坊,温柔呵护每一刻!'
  133. this.Gshare.path = `/pages_order/product/productDetail?id=${this.productDetail.id}`
  134. this.Gshare.imageUrl = this.bannerList[0] || ''
  135. // #ifdef H5
  136. // H5环境下重新设置微信分享
  137. this.setupWeixinShare()
  138. // #endif
  139. }
  140. },
  141. // 获取商品
  142. async fetchProductDetail(id) {
  143. try {
  144. this.productDetail = await this.$fetch('queryProductDetail', { id })
  145. // 商品数据加载完成后更新分享内容
  146. this.updateShareContent()
  147. } catch (err) {
  148. }
  149. },
  150. // 立即下单
  151. submit() {
  152. this.$store.commit('setPayOrderProduct', [
  153. this.productDetail
  154. ])
  155. this.$utils.navigateTo('/pages_order/order/createOrder')
  156. },
  157. }
  158. }
  159. </script>
  160. <style scoped lang="scss">
  161. $bar-height: 132rpx;
  162. .page {
  163. padding-bottom: calc(#{$bar-height} + env(safe-area-inset-bottom));
  164. background-color: #F3F3F3;
  165. /deep/ .nav-bar__view {
  166. background-image: linear-gradient(#84A73F, #D8FF8F);
  167. }
  168. .overview {
  169. padding: 16rpx 31rpx 18rpx 24rpx;
  170. background-color: $uni-fg-color;
  171. .sale {
  172. justify-content: space-between;
  173. color: #949494;
  174. font-size: 20rpx;
  175. .price {
  176. color: #FF2A2A;
  177. font-size: 45rpx;
  178. &-unit {
  179. font-size: 30rpx;
  180. margin-right: 3rpx;
  181. }
  182. .tag {
  183. font-size: 18rpx;
  184. font-weight: 700;
  185. padding: 9rpx 12rpx 9rpx 19rpx;
  186. margin-left: 15rpx;
  187. .icon {
  188. width: 27rpx;
  189. height: 19rpx;
  190. margin-right: 3rpx;
  191. }
  192. }
  193. &.member-personal {
  194. color: $uni-color-light;
  195. .tag {
  196. background-color: rgba($color: #D8FF8F, $alpha: 0.72);
  197. }
  198. }
  199. &.member-business {
  200. color: #FFB465;
  201. .tag {
  202. background-color: rgba($color: #FFFBC4, $alpha: 0.72);
  203. }
  204. }
  205. }
  206. }
  207. .title {
  208. color: #3A3A3A;
  209. font-size: 28rpx;
  210. font-weight: 700;
  211. margin-top: 15rpx;
  212. }
  213. .desc {
  214. justify-content: space-between;
  215. margin-top: 20rpx;
  216. .tag {
  217. color: #949494;
  218. font-size: 22rpx;
  219. .dot {
  220. width: 8rpx;
  221. height: 8rpx;
  222. border-radius: 50%;
  223. background-color: #949494;
  224. margin-right: 16rpx;
  225. }
  226. }
  227. }
  228. }
  229. .detail {
  230. margin-top: 12rpx;
  231. padding: 18rpx 28rpx;
  232. background-color: $uni-fg-color;
  233. .header {
  234. margin-bottom: 30rpx;
  235. }
  236. }
  237. .bar {
  238. position: fixed;
  239. bottom: 0;
  240. left: 0;
  241. width: 100vw;
  242. height: $bar-height;
  243. padding-bottom: env(safe-area-inset-bottom);
  244. background-color: $uni-fg-color;
  245. .count {
  246. flex: 1;
  247. color: #000000;
  248. font-size: 28rpx;
  249. margin-left: 29rpx;
  250. padding-left: 40rpx;
  251. border-left: 1rpx solid #B3997E;
  252. justify-content: flex-start;
  253. .price {
  254. color: #FF2A2A;
  255. font-size: 30rpx;
  256. &-unit {
  257. font-size: 18rpx;
  258. }
  259. }
  260. }
  261. .btn {
  262. border: none;
  263. line-height: 1;
  264. background-color: transparent;
  265. padding: 0;
  266. width: auto;
  267. height: auto;
  268. margin: 0;
  269. &-share {
  270. margin-left: 58rpx;
  271. color: #000000;
  272. font-size: 22rpx;
  273. &-icon {
  274. width: 48rpx;
  275. height: 50rpx;
  276. margin-bottom: 11rpx;
  277. }
  278. }
  279. &-pay {
  280. margin-right: 27rpx;
  281. padding: 24rpx 137rpx;
  282. color: $uni-text-color-inverse;
  283. font-size: 28rpx;
  284. border-radius: 44rpx;
  285. background-image: linear-gradient(to right, #84A73F, #D8FF8F);
  286. }
  287. }
  288. }
  289. }
  290. </style>