goods.vue 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. <template>
  2. <view :style="themeColor()">
  3. <view class="bg-page min-h-screen overflow-hidden ">
  4. <mescroll-body ref="mescrollRef" top="0" @init="mescrollInit" :down="{ use: false }" @up="getCollectListFn">
  5. <view class="py-[var(--top-m)] sidebar-margin" v-if="goodsList.length">
  6. <view class="bg-[#fff] pb-[10rpx] box-border rounded-[var(--rounded-big)]" >
  7. <view class="flex mx-[var(--rounded-big)] pt-[var(--pad-top-m)] justify-between items-center box-border font-400 text-[24rpx] mb-[24rpx] leading-[30rpx]">
  8. <view class="flex items-baseline text-[24rpx] text-[#333]">
  9. <text>共</text>
  10. <text class="text-[32rpx] mx-[2rpx] text-[var(--price-text-color)]">{{ goodsList.length }}</text>
  11. <text>件商品</text>
  12. </view>
  13. <text @click="isEdit = !isEdit" class="text-[var(--text-color-light6)] text-[24rpx]">{{ isEdit ? '完成' : '管理' }}</text>
  14. </view>
  15. <u-swipe-action ref="swipeActive">
  16. <block v-for="(item, index) in goodsList" :key="index">
  17. <view class="py-[20rpx] overflow-hidden w-full">
  18. <u-swipe-action-item :options="cartOptions" @click="swipeClick(item)">
  19. <view class="flex px-[var(--pad-sidebar-m)]">
  20. <view class="self-center w-[58rpx] h-[60rpx] flex items-center" v-if="isEdit" @click.stop="item.checked = !item.checked">
  21. <text class=" iconfont text-primary text-[34rpx] w-[34rpx] h-[34rpx] rounded-[17rpx] overflow-hidden shrink-0" :class="{ 'iconxuanze1':item.checked,'bg-[#F5F5F5]':!item.checked}"></text>
  22. </view>
  23. <view class="flex flex-1" @click="toLink(item.goods.goods_id)">
  24. <view class="relative w-[200rpx] h-[200rpx] flex items-center justify-center rounded-[var(--goods-rounded-big)] overflow-hidden">
  25. <u--image radius="var(--goods-rounded-big)" width="200rpx" height="200rpx" :src="img(item.goods_cover_thumb_mid||'')" model="aspectFill">
  26. <template #error>
  27. <image class="w-[200rpx] h-[200rpx] rounded-[var(--goods-rounded-big)] overflow-hidden" :src="img('static/resource/images/diy/shop_default.jpg')" mode="aspectFill"></image>
  28. </template>
  29. </u--image>
  30. <view v-if="item.status == 0 " class="absolute left-0 top-0 w-[200rpx] h-[200rpx] leading-[200rpx] text-center " style="background-color: rgba(0,0,0,0.3);">
  31. <text class="text-[#fff] text-[28rpx]">已失效</text>
  32. </view>
  33. </view>
  34. <view class="flex flex-1 flex-wrap ml-[20rpx]">
  35. <view class="w-[100%] flex flex-col items-baseline">
  36. <view class="text-[#333] text-[28rpx] max-h-[80rpx] leading-[40rpx] multi-hidden font-400">{{ item.goods_name }}</view>
  37. <view class="box-border max-w-[376rpx] mt-[10rpx] px-[14rpx] h-[36rpx] leading-[36rpx] truncate text-[var(--text-color-light6)] bg-[#F5F5F5] text-[22rpx] rounded-[20rpx]" v-if="item.sku_name">{{ item.sku_name }}</view>
  38. </view>
  39. <view class="flex justify-between items-end self-end mt-[10rpx] w-[100%]">
  40. <view class="text-[var(--price-text-color)] price-font truncate max-w-[200rpx]">
  41. <text class="text-[24rpx] font-500">¥</text>
  42. <text class="text-[40rpx] font-500">{{ parseFloat(item.goods_sku.price).toFixed(2).split('.')[0] }}</text>
  43. <text class="text-[24rpx] font-500">.{{ parseFloat(item.goods_sku.price).toFixed(2).split('.')[1] }}</text>
  44. </view>
  45. </view>
  46. </view>
  47. </view>
  48. </view>
  49. </u-swipe-action-item>
  50. </view>
  51. </block>
  52. </u-swipe-action>
  53. </view>
  54. </view>
  55. <mescroll-empty v-if="!goodsList.length && loading" :option="{tip : '暂无收藏的商品'}"></mescroll-empty>
  56. </mescroll-body>
  57. <view v-if="goodsList.length && isEdit" class="flex h-[96rpx] items-center bg-[#fff] fixed left-0 right-0 bottom-0 pl-[30rpx] pr-[20rpx] box-solid mb-ios justify-between z-100">
  58. <view class="flex items-center" @click="selectAll">
  59. <text class="self-center iconfont text-primary text-[34rpx] mr-[10rpx] w-[34rpx] h-[34rpx] rounded-[17rpx] overflow-hidden flex-shrink-0" :class="{'iconxuanze1': goodsList.length == checkedNum, 'bg-color': goodsList.length != checkedNum }"></text>
  60. <text class="font-400 text-[#303133] text-[26rpx]">全选</text>
  61. </view>
  62. <button class="w-[180rpx] h-[70rpx] font-500 text-[26rpx] leading-[70rpx] !text-[#fff] m-0 rounded-full primary-btn-bg remove-border" @click="deleteCollectFn">取消收藏</button>
  63. </view>
  64. </view>
  65. </view>
  66. </template>
  67. <script setup lang="ts">
  68. import { ref, computed, nextTick } from 'vue';
  69. import { t } from '@/locale'
  70. import { img, redirect } from '@/utils/common';
  71. import { getCollectList, cancelCollect } from '@/addon/mall/api/goods';
  72. import MescrollBody from '@/components/mescroll/mescroll-body/mescroll-body.vue';
  73. import MescrollEmpty from '@/components/mescroll/mescroll-empty/mescroll-empty.vue';
  74. import useMescroll from '@/components/mescroll/hooks/useMescroll.js';
  75. import { onLoad, onPageScroll, onReachBottom } from '@dcloudio/uni-app';
  76. const { mescrollInit, downCallback, getMescroll } = useMescroll(onPageScroll, onReachBottom);
  77. const loading = ref<boolean>(false);
  78. const optionLoading = ref(false)
  79. const goodsList = ref<Array<any>>([]);
  80. const isEdit = ref(false)
  81. interface mescrollStructure {
  82. num: number,
  83. size: number,
  84. endSuccess: Function,
  85. [propName: string]: any
  86. }
  87. const getCollectListFn = (mescroll: mescrollStructure) => {
  88. loading.value = false;
  89. let data: object = {
  90. page: mescroll.num,
  91. limit: mescroll.size
  92. };
  93. getCollectList(data).then((res: any) => {
  94. let newArr = (res.data.data as Array<Object>);
  95. //设置列表数据
  96. if (mescroll.num == 1) {
  97. goodsList.value = []; //如果是第一页需手动制空列表
  98. }
  99. goodsList.value = goodsList.value.concat(newArr);
  100. mescroll.endSuccess(newArr.length);
  101. loading.value = true;
  102. }).catch(() => {
  103. loading.value = true;
  104. mescroll.endErr(); // 请求失败, 结束加载
  105. })
  106. }
  107. const cartOptions = ref([
  108. {
  109. text: t('delete'),
  110. style: {
  111. backgroundColor: '#EF000C',
  112. width: '100rpx',
  113. height: '100%',
  114. borderRadius: '10rpx'
  115. }
  116. }
  117. ]);
  118. const swipeActive = ref()
  119. // 商品取消收藏
  120. const swipeClick= (data: any)=>{
  121. if (optionLoading.value) return
  122. optionLoading.value = true
  123. cancelCollect({ goods_ids: [data.goods.goods_id] }).then((res: any) => {
  124. nextTick(() => {
  125. if (swipeActive.value) swipeActive.value.closeOther()
  126. })
  127. optionLoading.value = false
  128. getMescroll().resetUpScroll();
  129. })
  130. }
  131. //取消全部收藏
  132. const deleteCollectFn = () => {
  133. if (!checkedNum.value) {
  134. uni.showToast({ title: '请先选择收藏的商品', icon: 'none' })
  135. return
  136. }
  137. if (optionLoading.value) return
  138. optionLoading.value = true
  139. const ids: any = []
  140. goodsList.value.forEach((item: any) => {
  141. if (item.checked) ids.push(item.goods.goods_id)
  142. })
  143. cancelCollect({ goods_ids: ids }).then((res: any) => {
  144. optionLoading.value = false
  145. getMescroll().resetUpScroll();
  146. })
  147. }
  148. // 选中数量
  149. const checkedNum = computed(() => {
  150. let num = 0
  151. goodsList.value.forEach((item: any) => {
  152. item.checked && (num += 1)
  153. })
  154. return num
  155. })
  156. /**
  157. * 全选
  158. */
  159. const selectAll = () => {
  160. const checked = goodsList.value.length == checkedNum.value ? false : true
  161. goodsList.value.forEach((item: any) => {
  162. item.checked = checked
  163. })
  164. }
  165. // 商品详情
  166. const toLink = (id: any) => {
  167. redirect({ url: '/addon/mall/pages/goods/detail', param: { goods_id: id } })
  168. }
  169. </script>
  170. <style lang="scss" scoped>
  171. .bg-color{
  172. background-color: #f5f5f5;
  173. }
  174. :deep(.u-swipe-action-item__right){
  175. padding: 2rpx;
  176. }
  177. :deep(.u-swipe-action-item__right__button__wrapper){
  178. padding:0 10rpx !important;
  179. }
  180. :deep(.u-swipe-action-item__right__button__wrapper__text){
  181. font-size:24rpx !important;
  182. }
  183. </style>