details.vue 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <!-- 商品详情 -->
  2. <template>
  3. <div class="default-width py-5" v-if="state.goodsInfo && Object.keys(state.goodsInfo).length">
  4. <v-card class="carousel border-radius-8 white-bgc pa-5" style="width: 100%;">
  5. <div class=" d-flex">
  6. <!-- 图片展示-轮播 -->
  7. <div style="width: 500px; height: 500px;">
  8. <div v-if="selectedSkuPicUrl" class="selectedSkuImgBox" @mouseover="showSelectedSkuImg = true" @mouseleave="showSelectedSkuImg = false">
  9. <v-img :src="selectedSkuPicUrl" :aspect-ratio="1" style="border-radius: 8px;"></v-img>
  10. <v-btn
  11. v-show="showSelectedSkuImg"
  12. size="x-small"
  13. class="close px-3"
  14. :disabled="inputValue <= min || disabled"
  15. @click="selectedSkuPicUrl = ''"
  16. >关闭</v-btn>
  17. </div>
  18. <v-carousel v-else show-arrows="hover" cycle :model-value="0" :hide-delimiters="!carouselHover" @mouseover="carouselHover = true" @mouseleave="carouselHover = false">
  19. <v-carousel-item v-for="(imgUrl, i) in state.goodsInfo.sliderPicUrls" :key="'wareImg'+i" @click="null">
  20. <v-img :src="imgUrl" :aspect-ratio="1" style="border-radius: 8px;"></v-img>
  21. </v-carousel-item>
  22. </v-carousel>
  23. </div>
  24. <!-- s-select-sku 商品属性选择 -->
  25. <div style="flex: 1;" class="pl-10">
  26. <!-- 大标题 -->
  27. <div class="title-name">{{ state.goodsInfo?.name || '--' }}</div>
  28. <!-- 小标题 -->
  29. <div class="title-introduction">{{ state.goodsInfo?.introduction || '--' }}</div>
  30. <!-- 价格 -->
  31. <div class="prices my-5">
  32. <div class="price mr-3"><span>¥</span>{{ selectedSkuPrice}}</div>
  33. <div class="marketPrice" v-if="state.goodsInfo?.marketPrice">{{ selectedSkuMarketPrice}}</div>
  34. </div>
  35. <!-- 销量 -->
  36. <div class="salesCount mb-5 parameterColor"><span class="l-s-10">已售</span>:{{ state.goodsInfo?.salesCount || 0 }}</div>
  37. <!-- 属性选择组件 -->
  38. <selectSku
  39. v-if="showSelectSku"
  40. class="mb-7"
  41. :goodsInfo="state.goodsInfo"
  42. @change="onSkuChange"
  43. @buy="onBuy"
  44. ></selectSku>
  45. </div>
  46. </div>
  47. </v-card>
  48. <!-- 详情描述 detail-content-card -->
  49. <v-card class="carousel border-radius-8 white-bgc pa-5 mt-3" style="width: 100%;">
  50. <div class="resume-header">
  51. <div class="resume-title">
  52. 详情
  53. </div>
  54. </div>
  55. <describe v-if="state.goodsInfo?.description" class="detail-content-selector" :content="state.goodsInfo.description"></describe>
  56. </v-card>
  57. </div>
  58. </template>
  59. <script setup>
  60. defineOptions({name: 'goods-details'})
  61. import { getProductDetail } from '@/api/mall'
  62. import selectSku from './detailsComponents/s-select-sku.vue'
  63. import describe from './detailsComponents/describe.vue'
  64. import { ref, reactive } from 'vue'
  65. import { useRouter } from 'vue-router'
  66. import Snackbar from '@/plugins/snackbar'
  67. const router = useRouter()
  68. const { id } = router.currentRoute.value.params
  69. const selectedSkuPicUrl = ref('')
  70. const selectedSkuPrice = ref('')
  71. const selectedSkuMarketPrice = ref('')
  72. const showSelectSku = ref(false)
  73. const carouselHover = ref(false)
  74. const showSelectedSkuImg = ref(false)
  75. // 获取商品详情
  76. const getData = async () => {
  77. const obj = await getProductDetail({ id })
  78. if (!obj) return Snackbar.warning('未找到商品!')
  79. //
  80. // 加载到商品
  81. obj.sliderPicUrls = obj.sliderPicUrls || []
  82. state.skeletonLoading = false;
  83. state.goodsInfo = obj
  84. showSelectSku.value = true
  85. // // 加载是否收藏
  86. // if (isLogin.value) {
  87. // FavoriteApi.isFavoriteExists(state.goodsId, 'goods').then((res) => {
  88. // if (res.code !== 0) {
  89. // return;
  90. // }
  91. // state.goodsInfo.favorite = res.data;
  92. // });
  93. // }
  94. }
  95. getData()
  96. const calcPrice = (price) => { return price && (price-0) ? (price-0)/100 : '--' }
  97. const state = reactive({
  98. goodsId: 0,
  99. skeletonLoading: true, // SPU 加载中
  100. goodsInfo: {}, // SPU 信息
  101. showSelectSku: false, // 是否展示 SKU 选择弹窗
  102. selectedSku: {}, // 选中的 SKU
  103. settlementSku: {}, // 结算的 SKU:由于 selectedSku 不进行默认选中,所以初始使用结算价格最低的 SKU 作为基础展示
  104. showModel: false, // 是否展示 Coupon 优惠劵的弹窗
  105. couponInfo: [], // 可领取的 Coupon 优惠劵的列表
  106. showActivityModel: false, // 【满减送/限时折扣】是否展示 Activity 营销活动的弹窗
  107. rewardActivity: {}, // 【满减送】活动
  108. activityList: [], // 【秒杀/拼团/砍价】可参与的 Activity 营销活动的列表
  109. });
  110. // 规格变更
  111. function onSkuChange(e) {
  112. state.selectedSku = e;
  113. state.settlementSku = e;
  114. // console.log('onSkuChange:', e)
  115. selectedSkuPicUrl.value = state.selectedSku?.picUrl || ''
  116. if (selectedSkuPicUrl.value) showSelectedSkuImg.value = true
  117. selectedSkuPrice.value = calcPrice(state.selectedSku?.price || state.goodsInfo.price)
  118. selectedSkuMarketPrice.value = calcPrice(state.selectedSku?.marketPrice || state.goodsInfo.marketPrice)
  119. }
  120. const onBuy = async () => {
  121. Snackbar.warning('购买功能暂未开放,敬请期待!')
  122. }
  123. // function onBuy(sku) {
  124. // sheep.$router.go('/pages/order/confirm', {
  125. // data: JSON.stringify({
  126. // order_type: 'goods',
  127. // combinationActivityId: state.activity.id,
  128. // combinationHeadId: state.combinationHeadId,
  129. // items: [
  130. // {
  131. // skuId: sku.id,
  132. // count: sku.count,
  133. // },
  134. // ],
  135. // }),
  136. // });
  137. // }
  138. </script>
  139. <style lang="scss" scoped>
  140. .border-radius-8 {
  141. border-radius: 8px;
  142. }
  143. .title-name {
  144. font-size: 24px;
  145. line-height: 1.25;
  146. color: #000;
  147. margin-bottom: 12px;
  148. font-weight: bold;
  149. }
  150. .title-introduction {
  151. font-size: 18px;
  152. line-height: 1.5;
  153. color: #6b6b6b;
  154. }
  155. .parameterColor {
  156. color: #7a7a7a;
  157. }
  158. .prices {
  159. display: flex;
  160. align-items: flex-end;
  161. color: #ff5000;
  162. font-size: 28px;
  163. margin: 8px 0;
  164. }
  165. .price {
  166. font-weight: 600;
  167. span {
  168. font-size: 16px;
  169. }
  170. }
  171. .marketPrice {
  172. color: #b7b7b7;
  173. font-size: 16px;
  174. line-height: 34px;
  175. text-decoration: line-through;
  176. }
  177. .selectedSkuImgBox {
  178. position: relative;
  179. .close {
  180. position: absolute;
  181. bottom: 10px;
  182. right: 10px;
  183. }
  184. }
  185. </style>