木邻有你前端代码仓库
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.

349 lines
8.3 KiB

10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
10 months ago
  1. <template>
  2. <view class="goods-detail">
  3. <!-- 轮播图 -->
  4. <view class="banner-container">
  5. <uv-swiper
  6. indicator
  7. indicatorMode="dot"
  8. indicatorActiveColor="blue"
  9. height="700rpx"
  10. :loading="!imageList.length"
  11. :list="imageList"></uv-swiper>
  12. </view>
  13. <!-- 商品信息 -->
  14. <view class="goods-info">
  15. <!-- 积分信息 -->
  16. <view class="points-section">
  17. <image src="/static/积分图标.png" class="points-icon" mode="aspectFit"></image>
  18. <text class="points-text">{{ goodsData.price }}积分</text>
  19. </view>
  20. <!-- 商品标题 -->
  21. <view class="title-section">
  22. <text class="goods-title">{{ goodsData.title }}</text>
  23. </view>
  24. </view>
  25. <!-- 商品详情独立容器 -->
  26. <view class="detail-container">
  27. <!-- 商品详情标题 -->
  28. <view class="detail-title-section">
  29. <rich-text :nodes="goodsData.details"></rich-text>
  30. </view>
  31. <!-- 商品图集 -->
  32. <!-- <view class="gallery-section">
  33. <view class="gallery-grid">
  34. <image
  35. v-for="(img, index) in goodsData.image.split(',')"
  36. :key="index"
  37. :src="img"
  38. class="gallery-image"
  39. mode="aspectFill"
  40. @click="previewImage(img, goodsData.image.split(','))"
  41. ></image>
  42. </view>
  43. </view> -->
  44. </view>
  45. <!-- 底部操作栏 -->
  46. <view class="bottom-bar">
  47. <view class="stock-info">
  48. <text class="stock-text"> {{ goodsData.inventory }}/{{ goodsData.sales }}</text>
  49. <text class="stock-label">库存</text>
  50. </view>
  51. <view class="favorite-section" @click="toggleFavorite">
  52. <uv-icon name="heart" size="24" :color="goodsData.isCollection === 1 ? 'red' : '#cccccc'"></uv-icon>
  53. <text class="favorite-text">收藏</text>
  54. </view>
  55. <view class="exchange-btn" @click="onExchange">
  56. <text class="exchange-text">申请兑换</text>
  57. </view>
  58. </view>
  59. <GlobalPopup ref="globalPopupRef" />
  60. </view>
  61. </template>
  62. <script>
  63. export default {
  64. name: 'GoodsDetail',
  65. data() {
  66. return {
  67. goodsId: '',
  68. goodsData: {
  69. id: 1,
  70. name: '哪吒之魔童闹海新款首套装哪吒校内艺术手办树脂摆件学生小礼品',
  71. points: 100,
  72. category: '积分兑换',
  73. exchangeCount: 120,
  74. stock: 50,
  75. description: '这是一款美味的薄脆小饼干,口感酥脆,营养丰富。采用优质原料制作,无添加剂,适合全家人享用。每一口都能感受到浓郁的香味和酥脆的口感,是您休闲时光的最佳选择。',
  76. gallery: [
  77. '/static/商城_商品1.png',
  78. '/static/商城_商品2.png',
  79. '/static/bannerImage.png',
  80. '/static/商城_商品1.png',
  81. '/static/商城_商品2.png',
  82. '/static/bannerImage.png'
  83. ]
  84. }
  85. }
  86. },
  87. computed: {
  88. imageList() {
  89. if (this.goodsData.image) {
  90. return this.goodsData.image.split(',')
  91. }
  92. return []
  93. }
  94. },
  95. onLoad(options) {
  96. if (options.id) {
  97. this.goodsId = options.id;
  98. this.getGoodsDetail(options.id);
  99. }
  100. },
  101. methods: {
  102. async getGoodsDetail(id) {
  103. let params = {}
  104. if (uni.getStorageSync('token')) {
  105. params.token = uni.getStorageSync('token')
  106. }
  107. const res = await this.$api.shop.queryGoodsById({ goodsId: id, ...params })
  108. this.goodsData = res.result
  109. },
  110. async toggleFavorite() {
  111. const res = await this.$api.shop.collectionGoods({ goodsId: this.goodsId })
  112. uni.showToast({
  113. title: res.message,
  114. icon: res.code === 200 ? 'success' : 'none'
  115. });
  116. this.getGoodsDetail(this.goodsId)
  117. },
  118. previewImage(current, urls) {
  119. uni.previewImage({
  120. current: current,
  121. urls: urls
  122. });
  123. },
  124. onExchange() {
  125. uni.showModal({
  126. title: '确认兑换',
  127. content: `确定要用${this.goodsData.price}积分兑换${this.goodsData.title}吗?`,
  128. success: async (res) => {
  129. if (res.confirm) {
  130. try{
  131. const res2 = await this.$api.shop.buyGoods({
  132. goodsId: this.goodsId
  133. })
  134. this.$refs.globalPopupRef.open({
  135. content: '恭喜您兑换成功!',
  136. subContent: '请及时到社区领取商品!',
  137. titleType: 'exchange',
  138. popupType: 'success',
  139. closefn: () => {
  140. setTimeout(() => {
  141. uni.navigateBack()
  142. }, 300);
  143. }
  144. })
  145. }catch (error) {
  146. console.log(error);
  147. if(error.code === 500 && error.message === '商品库存不足,兑换失败'){
  148. this.$refs.globalPopupRef.open({
  149. content: '库存不足!',
  150. subContent: '库存不足暂时不能兑换哦!',
  151. titleType: 'exchange',
  152. popupType: 'fail',
  153. closefn: () => {
  154. setTimeout(() => {
  155. uni.navigateBack()
  156. }, 300);
  157. }
  158. })
  159. }else if(error.code === 500 && error.message === '积分不足,兑换失败'){
  160. this.$refs.globalPopupRef.open({
  161. content: '您的积分不够哦!',
  162. subContent: '可以参与更多活动获取积分哦!',
  163. titleType: 'exchange',
  164. popupType: 'fail',
  165. closefn: () => {
  166. setTimeout(() => {
  167. uni.navigateBack()
  168. }, 300);
  169. }
  170. })
  171. }
  172. }
  173. }
  174. }
  175. });
  176. }
  177. }
  178. }
  179. </script>
  180. <style lang="scss" scoped>
  181. .goods-detail {
  182. background: #f8f8f8;
  183. min-height: 100vh;
  184. padding-bottom: 120rpx; // 为底部固定栏留出空间
  185. }
  186. .banner-container {
  187. height: 700rpx;
  188. .banner-swiper {
  189. width: 100%;
  190. .banner-image {
  191. width: 100%;
  192. height: 100%;
  193. }
  194. }
  195. }
  196. .goods-info {
  197. background: #ffffff;
  198. margin-top: 20rpx;
  199. padding: 30rpx;
  200. }
  201. .points-section {
  202. display: flex;
  203. align-items: center;
  204. margin-bottom: 20rpx;
  205. .points-icon {
  206. width: 32rpx;
  207. height: 32rpx;
  208. margin-right: 8rpx;
  209. }
  210. .points-text {
  211. font-size: 32rpx;
  212. font-weight: bold;
  213. color: #1488DB;
  214. }
  215. }
  216. .title-section {
  217. margin-bottom: 40rpx;
  218. .goods-title {
  219. font-size: 28rpx;
  220. color: #333333;
  221. line-height: 1.5;
  222. display: block;
  223. }
  224. }
  225. .detail-container {
  226. background: #ffffff;
  227. margin-top: 20rpx;
  228. padding: 30rpx;
  229. margin-bottom: 120rpx;
  230. }
  231. .detail-title-section {
  232. display: flex;
  233. align-items: center;
  234. justify-content: center;
  235. margin-bottom: 30rpx;
  236. .detail-title {
  237. font-size: 28rpx;
  238. font-weight: bold;
  239. color: #333333;
  240. }
  241. }
  242. .gallery-section {
  243. margin-bottom: 40rpx;
  244. .gallery-grid {
  245. display: grid;
  246. grid-template-columns: repeat(3, 1fr);
  247. gap: 16rpx;
  248. .gallery-image {
  249. width: 100%;
  250. height: 200rpx;
  251. border-radius: 12rpx;
  252. border: 1rpx solid #f0f0f0;
  253. }
  254. }
  255. }
  256. .bottom-bar {
  257. position: fixed;
  258. bottom: 0;
  259. left: 0;
  260. right: 0;
  261. background: #ffffff;
  262. padding: 20rpx 30rpx;
  263. border-top: 1rpx solid #f0f0f0;
  264. z-index: 999;
  265. box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
  266. display: flex;
  267. align-items: center;
  268. justify-content: space-between;
  269. .stock-info {
  270. display: flex;
  271. flex-direction: column;
  272. align-items: center;
  273. .stock-text {
  274. font-size: 24rpx;
  275. color: #1488DB;
  276. margin-bottom: 4rpx;
  277. font-weight: bold;
  278. }
  279. .stock-label {
  280. font-size: 22rpx;
  281. color: #999999;
  282. }
  283. }
  284. .favorite-section {
  285. flex: 1;
  286. display: flex;
  287. flex-direction: column;
  288. align-items: center;
  289. .favorite-text {
  290. font-size: 22rpx;
  291. color: #999999;
  292. margin-top: 4rpx;
  293. }
  294. }
  295. .exchange-btn {
  296. flex: 2;
  297. margin-left: 50rpx;
  298. height: 80rpx;
  299. border-radius: 40rpx;
  300. background-color: #1488DB;
  301. display: flex;
  302. align-items: center;
  303. justify-content: center;
  304. .exchange-text {
  305. color: #ffffff;
  306. font-size: 28rpx;
  307. // font-weight: bold;
  308. }
  309. }
  310. }
  311. </style>