Explorar el Código

fix(cart): 优化购物车功能及界面交互体验

- 修正删除商品确认框的逻辑,避免误操作
- 优化购物车商品选择状态和价格计算流程
- 改进商品明细展开的动画效果
- 为购物车列表添加空值判断,提高渲染稳定性
- 统一skuId类型转换,避免类型错误
- 增加购物车商品自动选中及同步更新选中状态
- 优化分类页选中分类初始化逻辑
- 修复多个组件样式冲突,增强样式隔离
- 修正优惠券跳转订单页面时参数类型问题
- 清理不必要的注释及日志输出,提高代码整洁度
zhangtao hace 1 semana
padre
commit
d384d9c940

+ 2 - 2
src/config/index.ts

@@ -6,10 +6,10 @@ const mapEnvVersion = {
   // develop: 'http://192.168.1.101:8080',
   // develop: 'http://192.168.0.157:8080',
   // develop: 'http://192.168.1.253:8080',
-  develop: 'http://192.168.0.19:8080', // 邓
+  // develop: 'http://192.168.0.19:8080', // 邓
   // develop: 'http://192.168.0.217:8080', // 黄
   // develop: 'http://192.168.0.11:8080', // 王
-  // develop: 'http://192.168.1.89:8080', // 田
+  develop: 'http://192.168.1.89:8080', // 田
   // develop: 'http://74949mkfh190.vicp.fun', // 付
   // develop: 'http://47.109.84.152:8081',
   // develop: 'https://5ed0f7cc.r9.vip.cpolar.cn',

+ 4 - 2
src/pages/cart/index.vue

@@ -173,8 +173,10 @@ async function handleSelectAddress() {
               <view v-if="totalProduct?.coupon" class="ml-10rpx text-24rpx text-[#FF4A39]">
                 共减¥{{ totalProduct?.coupon }}
               </view>
-              <view v-if="totalProduct?.amount" class="ml-10rpx text-24rpx text-gray" @click="priceDetailPopup = true">
-                明细 <wd-icon name="arrow-up" size="24rpx" color="#aaa" />
+              <view v-if="totalProduct?.amount" class="ml10rpx flex items-center text-24rpx text-gray" @click="priceDetailPopup = !priceDetailPopup">
+                明细 <view class="flex items-center" :class="[priceDetailPopup ? 'rotate-180' : '']">
+                  <wd-icon name="arrow-up" size="24rpx" color="#aaa" />
+                </view>
               </view>
             </view>
             <view class="mt-10rpx text-24rpx text-gray">

+ 6 - 2
src/store/cart.ts

@@ -184,11 +184,15 @@ export const useSmqjhCartStore = defineStore('smqjh-cart', {
         useGlobalToast().show({ msg: '移除商品中,请稍后' })
         return
       }
+      console.log(item.num, '===============================')
+
       if (item.num === 1) {
         useGlobalMessage().confirm({
           msg: '是否删除该商品?',
-          success: async () => {
-            await this.addCart(item.skuId, -1, item.shopId, 'XSB')
+          success: async ({ action }) => {
+            if (action === 'confirm') {
+              await this.addCart(item.skuId, -1, item.shopId, 'XSB')
+            }
           },
         })
       }

+ 5 - 3
src/subPack-xsb/commonTab/components/cart.vue

@@ -126,7 +126,7 @@ onMounted(async () => {
         </scroll-view>
       </view>
     </view>
-    <view class="fixedShadow fixed bottom-60rpx left-0 z-99 box-border w-full flex items-center justify-between rounded-t-16rpx bg-white px24rpx pb60rpx pt10rpx">
+    <view v-if="cartList.length" class="fixedShadow fixed bottom-60rpx left-0 z-99 box-border w-full flex items-center justify-between rounded-t-16rpx bg-white px24rpx pb60rpx pt10rpx">
       <view class="ios w-full flex items-center justify-between">
         <view class="flex items-center">
           <view class="flex items-center">
@@ -142,8 +142,10 @@ onMounted(async () => {
               <view v-if="totalProduct?.coupon" class="ml10rpx text-24rpx text-#FF4A39">
                 共减¥{{ totalProduct?.coupon }}
               </view>
-              <view v-if="totalProduct?.amount" class="ml10rpx text-24rpx text-gray" @click="priceDetailPopup = true">
-                明细 <wd-icon name="arrow-up" size="24rpx" color="#aaa" />
+              <view v-if="totalProduct?.amount" class="ml10rpx flex items-center text-24rpx text-gray" @click="priceDetailPopup = !priceDetailPopup">
+                明细 <view class="flex items-center" :class="[priceDetailPopup ? 'rotate-180' : '']">
+                  <wd-icon name="arrow-up" size="24rpx" color="#aaa" />
+                </view>
               </view>
             </view>
             <view class="mt10rpx text-24rpx text-gray">

+ 116 - 83
src/subPack-xsb/commonTab/components/classfiy.vue

@@ -47,6 +47,7 @@ async function handleClearCart() {
         totalProduct.value = undefined
         useSmqjhCartStore().getCartList('XSB')
         await getCartCategorList()
+        setProductNum()
       }
       finally {
         uni.hideLoading()
@@ -104,8 +105,6 @@ const categoriesId = computed(() => {
 })
 async function getCartCategorList() {
   return new Promise((resolve, reject) => {
-    // 记录刷新前的 ID 集合,用于检测新增商品
-    // const prevIdSet = new Set(cartList.value.map(it => it.id))
     Apis.xsb.myShoppingCartCategory({
       data: {
         businessType: 'XSB',
@@ -114,23 +113,7 @@ async function getCartCategorList() {
       },
     }).then((res) => {
       cartList.value = res.data
-      // const validIds = res.data
-      //   .filter(it => it.isDelete !== '1' && it.shopSkuStocks !== '0')
-      //   .map(it => it.id)
-      // // 保留仍有效的已选项 + 自动选中新添加的商品
-      // const newlyAdded = validIds.filter(id => !prevIdSet.has(id))
-      // const keepSelected = selectedIds.value.filter(id => validIds.includes(id))
-      // selectedIds.value = [...new Set([...keepSelected, ...newlyAdded])]
-      // // 第一次加载时全选
-      // if (selectedIds.value.length === 0 && validIds.length > 0) {
-      //   selectedIds.value = [...validIds]
-      // }
-      // if (cartList.value.length) {
-      //   getGoodsPrice()
-      // }
-      // else {
-      //   totalProduct.value = undefined
-      // }
+      console.log(cartList.value, '===================')
       resolve(res)
     }).catch((err) => {
       reject(err)
@@ -217,41 +200,50 @@ async function handleAddCart(event: WechatMiniprogram.TouchEvent, item: Api.xsbC
   setTimeout(() => {
     showball.value = false
   }, 500)
-  await useSmqjhCartStore().addCart(item.skuList[0].skuId, 1, Number(item.shopId), 'XSB')
+  const skuId = item.skuList[0].skuId
+  await useSmqjhCartStore().addCart(skuId, 1, Number(item.shopId), 'XSB')
   await getCartCategorList()
   setProductNum()
+  // 自动选中刚加入的商品,并重新计算价格
+  const cartItem = cartList.value.find(it => it.skuId === skuId && it.isDelete !== '1' && it.shopSkuStocks !== '0')
+  if (cartItem && !selectedIds.value.includes(cartItem.id)) {
+    selectedIds.value.push(cartItem.id)
+  }
+  await getGoodsPrice()
 }
 async function handleSubCart(event: WechatMiniprogram.TouchEvent, item: Api.xsbCategoryProductList) {
+  const skuId = item.skuList[0].skuId
   if (item.num === 1) {
     useGlobalMessage().confirm({
       msg: '是否删除该商品?',
       success: async () => {
-        await useSmqjhCartStore().addCart(item.skuList[0].skuId, -1, Number(item.shopId), 'XSB')
+        // 删除前记录 cartId,用于从 selectedIds 中移除
+        const cartItem = cartList.value.find(it => it.skuId === skuId)
+        await useSmqjhCartStore().addCart(skuId, -1, Number(item.shopId), 'XSB')
         await getCartCategorList()
         setProductNum()
-        totalProduct.value = undefined
+        if (cartItem) {
+          selectedIds.value = selectedIds.value.filter(id => id !== cartItem.id)
+        }
+        await getGoodsPrice()
       },
     })
   }
   else {
-    if (showball.value)
-      return
-    basllObj.value.left = event.detail.x
-    basllObj.value.top = event.detail.y
-    showball.value = true
-    setTimeout(() => {
-      showball.value = false
-    }, 500)
-    await useSmqjhCartStore().addCart(item.skuList[0].skuId, -1, Number(item.shopId), 'XSB')
+    await useSmqjhCartStore().addCart(skuId, -1, Number(item.shopId), 'XSB')
     await getCartCategorList()
     setProductNum()
+    await getGoodsPrice()
   }
 }
 
 onMounted(async () => {
   if (!topNavActive.value || !leftActive.value) {
-    topNavActive.value = props.categoryList && props.categoryList[0].code
-    leftActive.value = props.categoryList[0].children && props.categoryList[0].children[0].code
+    const firstWithChildren = props.categoryList?.find(it => it.children && it.children.length > 0)
+    if (firstWithChildren) {
+      topNavActive.value = firstWithChildren.code
+      leftActive.value = firstWithChildren.children![0].code
+    }
   }
   goodsLoading.value = 'loading'
   if (leftActive.value) {
@@ -266,7 +258,7 @@ onMounted(async () => {
       topScrollView.value = topNavActive.value
     })
   }
-  console.log(topNavActive.value, '  ==', leftActive.value)
+  console.log(topNavActive.value, '  ==', props.categoryList)
 
   getCartBox()
   if (token.value) {
@@ -391,6 +383,14 @@ function handlePay() {
 }
 </script>
 
+<script lang="ts">
+export default {
+  options: {
+    styleIsolation: 'shared',
+  },
+}
+</script>
+
 <template>
   <view class="page-xsb">
     <wd-navbar
@@ -435,13 +435,16 @@ function handlePay() {
             class="mr24rpx flex flex-col items-center justify-center" @click="handleTopNavChange(item)"
           >
             <view class="relative">
-              <view class="box-border" :class="[topNavActive == item.code ? 'overflow-hidden border-solid border-[var(--them-color)] border-2rpx rounded-26rpx h84rpx w-84rpx' : 'h72rpx w-72rpx']">
-                <image
-                  :src="item.icon"
-                  class="h-full w-full"
-                />
+              <view
+                class="box-border"
+                :class="[topNavActive == item.code ? 'overflow-hidden border-solid border-[var(--them-color)] border-2rpx rounded-26rpx h84rpx w-84rpx' : 'h72rpx w-72rpx']"
+              >
+                <image :src="item.icon" class="h-full w-full" />
               </view>
-              <view v-if="!item.children" class="absolute left-0 top-0 h-full w-full flex items-center justify-center rounded-26rpx bg-[rgba(0,0,0,0.6)] text-16rpx text-white">
+              <view
+                v-if="!item.children"
+                class="absolute left-0 top-0 h-full w-full flex items-center justify-center rounded-26rpx bg-[rgba(0,0,0,0.6)] text-16rpx text-white"
+              >
                 敬请期待
               </view>
             </view>
@@ -500,10 +503,21 @@ function handlePay() {
       </wd-popup>
     </view>
     <view class="wraper">
-      <scroll-view class="w200rpx" :scroll-into-view-offset="-150" enable-passive scroll-with-animation scroll-y :scroll-into-view="`id${leftActive}`">
-        <view v-for="item in categories" :id="`id${item.code}`" :key="item.code" :class="[item.code == leftActive ? 'bg-white' : '']" class="relative h100rpx flex items-center justify-center whitespace-nowrap text-28rpx" @click="handleLeftChange(item)">
+      <scroll-view
+        class="w200rpx" :scroll-into-view-offset="-150" enable-passive scroll-with-animation scroll-y
+        :scroll-into-view="`id${leftActive}`"
+      >
+        <view
+          v-for="item in categories" :id="`id${item.code}`" :key="item.code"
+          :class="[item.code == leftActive ? 'bg-white' : '']"
+          class="relative h100rpx flex items-center justify-center whitespace-nowrap text-28rpx"
+          @click="handleLeftChange(item)"
+        >
           {{ item.name }}
-          <view v-if="item.code == leftActive" class="absolute left-0 top-20rpx h60rpx w8rpx rounded-4rpx bg-[var(--them-color)]" />
+          <view
+            v-if="item.code == leftActive"
+            class="absolute left-0 top-20rpx h60rpx w8rpx rounded-4rpx bg-[var(--them-color)]"
+          />
         </view>
       </scroll-view>
       <view class="content">
@@ -518,23 +532,17 @@ function handlePay() {
         </view>
         <view class="relative">
           <scroll-view
-            :lower-threshold="100"
-            :refresher-triggered="isTopLoading" :scroll-top="scrollTop"
-            :style="{ height: `calc(100vh - ${navHeight} - 700rpx)` }" enable-passive scroll-y scroll-anchoring refresher-enabled :throttle="false"
-            :scroll-into-view="`class${goodsInTo}`"
-
-            @refresherrefresh="handleSrollTop"
-            @scrolltolower="handlScrollBottom"
+            :lower-threshold="100" :refresher-triggered="isTopLoading" :scroll-top="scrollTop"
+            :style="{ height: `calc(100vh - ${navHeight} - 700rpx)` }" enable-passive scroll-y scroll-anchoring
+            refresher-enabled :throttle="false" :scroll-into-view="`class${goodsInTo}`"
+            @refresherrefresh="handleSrollTop" @scrolltolower="handlScrollBottom"
           >
             <view v-if="productList.length" class="p20rpx">
               <view v-for="item in productList" :id="`class${item.prodId}`" :key="item.id" class="relative">
                 <view class="flex" @click="handleGo(item)">
                   <view class="relative mr20rpx h172rpx w172rpx flex-shrink-0 overflow-hidden rounded-16rpx bg-#F6F6F6">
                     <image :src="item.pic" lazy-load class="h-full w-full" />
-                    <image
-                      :src="`${StaticUrl}/xsb-shui-class.png`"
-                      class="absolute left-0 top-0 h-full w-full"
-                    />
+                    <image :src="`${StaticUrl}/xsb-shui-class.png`" class="absolute left-0 top-0 h-full w-full" />
                   </view>
                   <view class="flex-1">
                     <view class="text-left text-28rpx font-semibold">
@@ -572,16 +580,16 @@ function handlePay() {
                       <view v-else>
                         <view class="flex items-center">
                           <image
-                            :src="` ${StaticUrl}/sub-cart.png`"
-                            class="h44rpx w44rpx"
+                            :src="` ${StaticUrl}/sub-cart.png`" class="h44rpx w44rpx"
                             @click.stop="handleSubCart($event, item)"
                           />
-                          <view class="box-border h44rpx w84rpx flex items-center justify-center border border-#F0F0F0 border-solid text-24rpx text-#AAAAAA">
+                          <view
+                            class="box-border h44rpx w84rpx flex items-center justify-center border border-#F0F0F0 border-solid text-24rpx text-#AAAAAA"
+                          >
                             {{ item.num }}
                           </view>
                           <image
-                            :src="` ${StaticUrl}/add-cart.png`"
-                            class="h44rpx w44rpx"
+                            :src="` ${StaticUrl}/add-cart.png`" class="h44rpx w44rpx"
                             @click.stop="handleAddCart($event, item)"
                           />
                         </view>
@@ -592,16 +600,26 @@ function handlePay() {
                 <view class="line">
                   <wd-divider color="#F0F0F0" />
                 </view>
-                <view v-if="!item.spuStock" class="absolute left-0 top-0 z-1 h-full w-full flex items-center bg-[rgba(255,255,255,.6)]">
+                <view
+                  v-if="!item.spuStock"
+                  class="absolute left-0 top-0 z-1 h-full w-full flex items-center bg-[rgba(255,255,255,.6)]"
+                >
                   <view class="h172rpx w172rpx flex items-center justify-center">
-                    <view class="h36rpx w112rpx flex items-center justify-center rounded-16rpx bg-[rgba(0,0,0,.6)] text-28rpx text-white">
+                    <view
+                      class="h36rpx w112rpx flex items-center justify-center rounded-16rpx bg-[rgba(0,0,0,.6)] text-28rpx text-white"
+                    >
                       已售罄
                     </view>
                   </view>
                 </view>
-                <view v-if="!item.skuList.some((it) => it.saleStatus)" class="absolute left-0 top-0 z-1 h-full w-full flex items-center bg-[rgba(255,255,255,.6)]">
+                <view
+                  v-if="!item.skuList.some((it) => it.saleStatus)"
+                  class="absolute left-0 top-0 z-1 h-full w-full flex items-center bg-[rgba(255,255,255,.6)]"
+                >
                   <view class="h172rpx w172rpx flex items-center justify-center">
-                    <view class="h36rpx w112rpx flex items-center justify-center rounded-16rpx bg-[rgba(0,0,0,.6)] text-28rpx text-white">
+                    <view
+                      class="h36rpx w112rpx flex items-center justify-center rounded-16rpx bg-[rgba(0,0,0,.6)] text-28rpx text-white"
+                    >
                       不可售
                     </view>
                   </view>
@@ -611,7 +629,10 @@ function handlePay() {
             <StatusTip v-else tip="暂无内容" />
             <view v-if="goodsLoading == 'finished' || isTopLoading" class="h-40vh" />
           </scroll-view>
-          <view v-if="goodsLoading == 'loading' || isTopLoading" class="absolute left-0 top-0 z-10 h-full w-full flex items-center justify-center bg-white">
+          <view
+            v-if="goodsLoading == 'loading' || isTopLoading"
+            class="absolute left-0 top-0 z-10 h-full w-full flex items-center justify-center bg-white"
+          >
             <wd-loading color="#9ED605" :size="20" />
           </view>
         </view>
@@ -635,8 +656,13 @@ function handlePay() {
               <view v-if="totalProduct?.coupon" class="ml10rpx text-24rpx text-#FF4A39">
                 共减¥{{ totalProduct?.coupon }}
               </view>
-              <view v-if="totalProduct?.amount" class="ml10rpx text-24rpx text-gray" @click="priceDetailPopup = true, cartPopup = false">
-                明细 <wd-icon name="arrow-up" size="24rpx" color="#aaa" />
+              <view
+                v-if="totalProduct?.amount" class="ml10rpx flex items-center text-24rpx text-gray"
+                @click="priceDetailPopup = !priceDetailPopup, cartPopup = false"
+              >
+                明细 <view :class="[priceDetailPopup ? 'rotate-180' : '']" class="flex items-center">
+                  <wd-icon name="arrow-up" size="24rpx" color="#aaa" />
+                </view>
               </view>
             </view>
             <view class="mt10rpx text-24rpx text-gray">
@@ -739,23 +765,20 @@ function handlePay() {
         <!-- 商品列表 -->
         <view class="h-700rpx overflow-y-scroll">
           <view class="p-24rpx">
-            <wd-checkbox-group v-model="selectedIds" @change="getGoodsPrice">
+            <wd-checkbox-group v-model="selectedIds" custom-class="custom-checkbox-group" @change="getGoodsPrice">
               <view
                 v-for="item in cartList" :key="item.id"
                 class="relative mt-20rpx box-border flex items-center overflow-hidden rounded-16rpx bg-white p-24rpx"
               >
                 <!-- 复选框 -->
                 <wd-checkbox
-                  v-if="item.shopSkuStocks !== '0' && item.isDelete !== '1'"
-                  :model-value="item.id"
-                  size="large"
-                  class="mr-16rpx flex-shrink-0"
+                  v-if="item.shopSkuStocks !== '0' && item.isDelete !== '1'" :model-value="item.id"
+                  size="large" class="mr-16rpx flex-shrink-0"
                 />
                 <view v-else class="mr-16rpx h-40rpx w-40rpx flex-shrink-0" />
                 <view class="flex flex-1">
                   <image
-                    :src="item.pic"
-                    class="h206rpx w200rpx flex-shrink-0"
+                    :src="item.pic" class="h206rpx w200rpx flex-shrink-0"
                     @click.stop="router.push({ name: 'xsb-goods', params: { id: String(item.prodId) } })"
                   />
                   <view class="ml20rpx flex-1">
@@ -771,23 +794,26 @@ function handlePay() {
                       </view>
                       <view v-if="item.shopSkuStocks !== '0' && item.isDelete !== '1'" class="flex items-center">
                         <image
-                          :src="` ${StaticUrl}/sub-cart.png`"
-                          class="h44rpx w44rpx"
+                          :src="` ${StaticUrl}/sub-cart.png`" class="h44rpx w44rpx"
                           @click.stop="handleSub(item)"
                         />
-                        <view class="box-border h44rpx w84rpx flex items-center justify-center border border-#F0F0F0 border-solid text-24rpx text-#AAAAAA">
+                        <view
+                          class="box-border h44rpx w84rpx flex items-center justify-center border border-#F0F0F0 border-solid text-24rpx text-#AAAAAA"
+                        >
                           {{ item.num }}
                         </view>
                         <image
-                          :src="` ${StaticUrl}/add-cart.png`"
-                          class="h44rpx w44rpx"
+                          :src="` ${StaticUrl}/add-cart.png`" class="h44rpx w44rpx"
                           @click.stop="handleAdd(item)"
                         />
                       </view>
                     </view>
                   </view>
                 </view>
-                <view v-if="item.shopSkuStocks == '0' || item.isDelete == '1'" class="absolute left-0 top-0 z-1 h-full w-full bg-[rgba(255,255,255,.6)]">
+                <view
+                  v-if="item.shopSkuStocks == '0' || item.isDelete == '1'"
+                  class="absolute left-0 top-0 z-1 h-full w-full bg-[rgba(255,255,255,.6)]"
+                >
                   <view class="relative w-full flex items-center justify-center">
                     <view class="rounded-16rpx bg-[rgba(0,0,0,.5)] p20rpx text-white">
                       {{ item.shopSkuStocks == '0' ? '商品已售罄' : '商品已删除' }}
@@ -807,7 +833,10 @@ function handlePay() {
         </view>
       </view>
     </Zpopup>
-    <selectSku v-model:show="selectGoods" v-model:sku-id="selectSkuId" v-model:select-goods-num="SelectGoodsNum" :goods-info="goodsInfo!">
+    <selectSku
+      v-model:show="selectGoods" v-model:sku-id="selectSkuId" v-model:select-goods-num="SelectGoodsNum"
+      :goods-info="goodsInfo!"
+    >
       <template #footer>
         <view class="box-border w-full flex items-center justify-between py20rpx">
           <view class="w-48%">
@@ -834,8 +863,9 @@ function handlePay() {
   background: linear-gradient(180deg, #FAFFEC 0%, #F6FFDE 11%, #E7FFA5 100%);
   box-shadow: -10rpx 0rpx 12rpx 2rpx rgba(0, 0, 0, 0.07);
 }
-.fixedShadow{
-    box-shadow: 0rpx -6rpx 12rpx 2rpx rgba(0,0,0,0.05);
+
+.fixedShadow {
+  box-shadow: 0rpx -6rpx 12rpx 2rpx rgba(0, 0, 0, 0.05);
 }
 
 .wraper {
@@ -872,6 +902,9 @@ function handlePay() {
 }
 
 .cart-img {
-  animation: moveY .5s cubic-bezier(1,-1.26,1,1) forwards;
+  animation: moveY .5s cubic-bezier(1, -1.26, 1, 1) forwards;
+}
+:deep(.wd-checkbox-group){
+  background-color: transparent !important;
 }
 </style>

+ 2 - 2
src/subPack-xsb/components/coupon/index.vue

@@ -69,10 +69,10 @@ function handleUseCoupon() {
         >
           去使用
         </view>
-        <wd-button v-if="itemcoupon.useStatus === 1" hairline plain size="small" type="info" @click="router.replace({ name: 'xsb-orderDetaile', params: { id: itemcoupon.lockOrderId } })">
+        <wd-button v-if="itemcoupon.useStatus === 1" plain hairline size="small" type="info" @click="router.replace({ name: 'xsb-orderDetaile', params: { id: String(itemcoupon.lockOrderId) } })">
           查看订单
         </wd-button>
-        <wd-button v-if="itemcoupon.useStatus === 7" hairline plain size="small" type="info" @click="router.replace({ name: 'xsb-orderDetaile', params: { id: itemcoupon.lockOrderId } })">
+        <wd-button v-if="itemcoupon.useStatus === 7" hairline plain size="small" type="info" @click="router.replace({ name: 'xsb-orderDetaile', params: { id: String(itemcoupon.lockOrderId) } })">
           去取消订单
         </wd-button>
       </view>