Przeglądaj źródła

【功能优化】商城:价格计算时,返回可用 + 不可用的优惠劵

Xiao_123 9 miesięcy temu
rodzic
commit
e10f8d388c

+ 110 - 50
pages/order/confirm.vue

@@ -41,36 +41,64 @@
           </view>
         </view>
         <view
+          v-if="state.orderPayload.pointActivityId"
           class="order-item ss-flex ss-col-center ss-row-between"
-          v-if="state.orderInfo.type === 0"
+        >
+          <view class="item-title">兑换积分</view>
+          <view class="ss-flex ss-col-center">
+            <image
+              :src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
+              class="score-img"
+            />
+            <text class="item-value ss-m-r-24">
+              {{ state.orderInfo.usePoint }}
+            </text>
+          </view>
+        </view>
+        <view
+          class="order-item ss-flex ss-col-center ss-row-between"
+          v-if="state.orderInfo.type === 0 || state.orderPayload.pointActivityId"
         >
           <view class="item-title">积分抵扣</view>
           <view class="ss-flex ss-col-center">
-            {{ state.pointStatus ? '剩余积分' : '当前积分' }}
+            {{ state.pointStatus || state.orderPayload.pointActivityId ? '剩余积分' : '当前积分' }}
             <image
               :src="sheep.$url.static('/static/img/shop/goods/score1.svg')"
               class="score-img"
             />
             <text class="item-value ss-m-r-24">
-              {{ state.pointStatus ? state.orderInfo.totalPoint - state.orderInfo.usePoint : (state.orderInfo.totalPoint || 0) }}
+              {{
+                state.pointStatus || state.orderPayload.pointActivityId
+                  ? state.orderInfo.totalPoint - state.orderInfo.usePoint
+                  : state.orderInfo.totalPoint || 0
+              }}
             </text>
-            <checkbox-group @change="changeIntegral">
-              <checkbox :checked='state.pointStatus' :disabled="!state.orderInfo.totalPoint || state.orderInfo.totalPoint <= 0" />
+            <checkbox-group @change="changeIntegral" v-if="!state.orderPayload.pointActivityId">
+              <checkbox
+                :checked="state.pointStatus"
+                :disabled="!state.orderInfo.totalPoint || state.orderInfo.totalPoint <= 0"
+              />
             </checkbox-group>
           </view>
         </view>
         <!-- 快递配置时,信息的展示 -->
-        <view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 1'>
+        <view
+          class="order-item ss-flex ss-col-center ss-row-between"
+          v-if="addressState.deliveryType === 1"
+        >
           <view class="item-title">运费</view>
           <view class="ss-flex ss-col-center">
             <text class="item-value ss-m-r-24" v-if="state.orderInfo.price.deliveryPrice > 0">
               +¥{{ fen2yuan(state.orderInfo.price.deliveryPrice) }}
             </text>
-            <view class='item-value ss-m-r-24' v-else>免运费</view>
+            <view class="item-value ss-m-r-24" v-else>免运费</view>
           </view>
         </view>
         <!-- 门店自提时,需要填写姓名和手机号 -->
-        <view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 2'>
+        <view
+          class="order-item ss-flex ss-col-center ss-row-between"
+          v-if="addressState.deliveryType === 2"
+        >
           <view class="item-title">联系人</view>
           <view class="ss-flex ss-col-center">
             <uni-easyinput
@@ -82,7 +110,10 @@
             />
           </view>
         </view>
-        <view class="order-item ss-flex ss-col-center ss-row-between" v-if='addressState.deliveryType === 2'>
+        <view
+          class="order-item ss-flex ss-col-center ss-row-between"
+          v-if="addressState.deliveryType === 2"
+        >
           <view class="item-title">联系电话</view>
           <view class="ss-flex ss-col-center">
             <uni-easyinput
@@ -106,11 +137,17 @@
             </text>
             <text
               class="item-value"
-              :class="state.couponInfo.length > 0 ? 'text-red' : 'text-disabled'"
+              :class="
+                state.couponInfo.filter((coupon) => coupon.match).length > 0
+                  ? 'text-red'
+                  : 'text-disabled'
+              "
               v-else
             >
               {{
-                state.couponInfo.length > 0 ? state.couponInfo.length + ' 张可用' : '暂无可用优惠券'
+                state.couponInfo.filter((coupon) => coupon.match).length > 0
+                  ? state.couponInfo.filter((coupon) => coupon.match).length + ' 张可用'
+                  : '暂无可用优惠券'
               }}
             </text>
             <text class="_icon-forward item-icon" />
@@ -121,8 +158,7 @@
           v-if="state.orderInfo.price.discountPrice > 0"
         >
           <view class="item-title">活动优惠</view>
-          <view class="ss-flex ss-col-center">
-            <!--                @tap="state.showDiscount = true" TODO 芋艿:后续要把优惠信息打进去 -->
+          <view class="ss-flex ss-col-center" @tap="state.showDiscount = true">
             <text class="item-value text-red">
               -¥{{ fen2yuan(state.orderInfo.price.discountPrice) }}
             </text>
@@ -158,7 +194,7 @@
       @close="state.showCoupon = false"
     />
 
-    <!-- 满额折扣弹框 TODO 芋艿:后续要把优惠信息打进去 -->
+    <!-- 满额折扣弹框 TODO @puhui999:【折扣】后续要把优惠信息打进去 -->
     <s-discount-list
       v-model="state.orderInfo"
       :show="state.showDiscount"
@@ -190,7 +226,7 @@
   import AddressSelection from '@/pages/order/addressSelection.vue';
   import sheep from '@/sheep';
   import OrderApi from '@/sheep/api/trade/order';
-  import CouponApi from '@/sheep/api/promotion/coupon';
+  import TradeConfigApi from '@/sheep/api/trade/config';
   import { fen2yuan } from '@/sheep/hooks/useGoods';
 
   const state = reactive({
@@ -208,8 +244,8 @@
 
   const addressState = ref({
     addressInfo: {}, // 选择的收货地址
-    deliveryType: 1, // 收货方式:1-快递配送,2-门店自提
-    isPickUp: true, // 门店自提是否开启 TODO puhui999: 默认开启,看看后端有开关的话接入
+    deliveryType: undefined, // 收货方式:1-快递配送,2-门店自提
+    isPickUp: true, // 门店自提是否开启
     pickUpInfo: {}, // 选择的自提门店信息
     receiverName: '', // 收件人名称
     receiverMobile: '', // 收件人手机
@@ -226,19 +262,11 @@
 
   // 选择优惠券
   async function onSelectCoupon(couponId) {
-    state.orderPayload.couponId = couponId
+    state.orderPayload.couponId = couponId;
     await getOrderInfo();
     state.showCoupon = false;
   }
 
-  // 使用 watch 监听地址和配送方式的变化
-  watch(addressState, async (newAddress, oldAddress) => {
-    // 如果收货地址或配送方式有变化,则重新计算价格
-    if (newAddress.addressInfo.id !== oldAddress.addressInfo.id || newAddress.deliveryType !== oldAddress.deliveryType) {
-      await getOrderInfo();
-    }
-  });
-
   // 提交订单
   function onConfirm() {
     if (addressState.value.deliveryType === 1 && !addressState.value.addressInfo.id) {
@@ -274,13 +302,14 @@
       remark: state.orderPayload.remark,
       deliveryType: addressState.value.deliveryType,
       addressId: addressState.value.addressInfo.id, // 收件地址编号
-      pickUpStoreId: addressState.value.pickUpInfo.id,//自提门店编号
-      receiverName: addressState.value.receiverName,// 选择门店自提时,该字段为联系人名
-      receiverMobile: addressState.value.receiverMobile,// 选择门店自提时,该字段为联系人手机
+      pickUpStoreId: addressState.value.pickUpInfo.id, //自提门店编号
+      receiverName: addressState.value.receiverName, // 选择门店自提时,该字段为联系人名
+      receiverMobile: addressState.value.receiverMobile, // 选择门店自提时,该字段为联系人手机
       pointStatus: state.pointStatus,
       combinationActivityId: state.orderPayload.combinationActivityId,
       combinationHeadId: state.orderPayload.combinationHeadId,
       seckillActivityId: state.orderPayload.seckillActivityId,
+      pointActivityId: state.orderPayload.pointActivityId,
     });
     if (code !== 0) {
       return;
@@ -291,9 +320,15 @@
     }
 
     // 跳转到支付页面
-    sheep.$router.redirect('/pages/pay/index', {
-      id: data.payOrderId,
-    });
+    if (data.payOrderId && data.payOrderId > 0) {
+      sheep.$router.redirect('/pages/pay/index', {
+        id: data.payOrderId,
+      });
+    } else {
+      sheep.$router.redirect('/pages/order/detail', {
+        id: data.id,
+      });
+    }
   }
 
   // 检查库存 & 计算订单价格
@@ -304,45 +339,70 @@
       couponId: state.orderPayload.couponId,
       deliveryType: addressState.value.deliveryType,
       addressId: addressState.value.addressInfo.id, // 收件地址编号
-      pickUpStoreId: addressState.value.pickUpInfo.id,//自提门店编号
-      receiverName: addressState.value.receiverName,// 选择门店自提时,该字段为联系人名
-      receiverMobile: addressState.value.receiverMobile,// 选择门店自提时,该字段为联系人手机
+      pickUpStoreId: addressState.value.pickUpInfo.id, //自提门店编号
+      receiverName: addressState.value.receiverName, // 选择门店自提时,该字段为联系人名
+      receiverMobile: addressState.value.receiverMobile, // 选择门店自提时,该字段为联系人手机
       pointStatus: state.pointStatus,
       combinationActivityId: state.orderPayload.combinationActivityId,
       combinationHeadId: state.orderPayload.combinationHeadId,
       seckillActivityId: state.orderPayload.seckillActivityId,
+      pointActivityId: state.orderPayload.pointActivityId,
     });
     if (code !== 0) {
-      return;
+      return code;
     }
     state.orderInfo = data;
+    state.couponInfo = data.coupons || [];
     // 设置收货地址
     if (state.orderInfo.address) {
       addressState.value.addressInfo = state.orderInfo.address;
     }
-  }
-
-  // 获取可用优惠券
-  async function getCoupons() {
-    const { code, data } = await CouponApi.getMatchCouponList(
-      state.orderInfo.price.payPrice,
-      state.orderInfo.items.map((item) => item.spuId),
-      state.orderPayload.items.map((item) => item.skuId),
-      state.orderPayload.items.map((item) => item.categoryId),
-    );
-    if (code === 0) {
-      state.couponInfo = data;
-    }
+    return code;
   }
 
   onLoad(async (options) => {
+    // 解析参数
     if (!options.data) {
       sheep.$helper.toast('参数不正确,请检查!');
       return;
     }
     state.orderPayload = JSON.parse(options.data);
+
+    // 获取交易配置
+    const { data, code } = await TradeConfigApi.getTradeConfig();
+    if (code === 0) {
+      addressState.value.isPickUp = data.deliveryPickUpEnabled;
+    }
+
+    // 价格计算
+    // 情况一:先自动选择“快递物流”
+    addressState.value.deliveryType = 1;
+    let orderCode = await getOrderInfo();
+    if (orderCode === 0) {
+      return;
+    }
+    // 情况二:失败,再自动选择“门店自提”
+    if (addressState.value.isPickUp) {
+      addressState.value.deliveryType = 2;
+      let orderCode = await getOrderInfo();
+      if (orderCode === 0) {
+        return;
+      }
+    }
+    // 情况三:都失败,则不选择
+    addressState.value.deliveryType = undefined;
     await getOrderInfo();
-    await getCoupons();
+  });
+
+  // 使用 watch 监听地址和配送方式的变化
+  watch(addressState, async (newAddress, oldAddress) => {
+    // 如果收货地址或配送方式有变化,则重新计算价格
+    if (
+      newAddress.addressInfo.id !== oldAddress.addressInfo.id ||
+      newAddress.deliveryType !== oldAddress.deliveryType
+    ) {
+      await getOrderInfo();
+    }
   });
 </script>
 

+ 43 - 39
pages/user/goods_details_store/index.vue

@@ -1,48 +1,52 @@
 <template>
   <s-layout title="选择自提门店" :bgStyle="{ color: '#FFF' }">
     <view class="storeBox" ref="container">
-      <s-empty v-if="!state.storeList.length" icon="/static/order-empty.png" text="暂无自提门店" />
-      <view v-else>
-        <view class="storeBox-box" v-for="(item, index) in state.storeList" :key="index" @tap="checked(item)">
-          <view class="store-img">
-            <image :src="item.logo" class="img" />
-          </view>
-          <view class="store-cent-left">
-            <view class="store-name">{{ item.name }}</view>
-            <view class="store-address line1">
-              {{ item.areaName }}{{ ', ' + item.detailAddress }}
-            </view>
+      <view
+        class="storeBox-box"
+        v-for="(item, index) in state.storeList"
+        :key="index"
+        @tap="checked(item)"
+      >
+        <view class="store-img">
+          <image :src="item.logo" class="img" />
+        </view>
+        <view class="store-cent-left">
+          <view class="store-name">{{ item.name }}</view>
+          <view class="store-address line1">
+            {{ item.areaName }}{{ ', ' + item.detailAddress }}
           </view>
-          <view class="row-right ss-flex-col ss-col-center">
-            <view>
-              <!-- #ifdef H5 -->
-              <a class="store-phone" :href="'tel:' + item.phone">
-                <view class="iconfont">
-                  <view class="ss-rest-button">
-                    <text class="_icon-forward" />
-                  </view>
-                </view>
-              </a>
-              <!-- #endif -->
-              <!-- #ifdef MP -->
-              <view class="store-phone" @click="call(item.phone)">
-                <view class="iconfont">
-                  <view class="ss-rest-button">
-                    <text class="_icon-forward" />
-                  </view>
+        </view>
+        <view class="row-right ss-flex-col ss-col-center">
+          <view>
+            <!-- #ifdef H5 -->
+            <a class="store-phone" :href="'tel:' + item.phone">
+              <view class="iconfont">
+                <view class="ss-rest-button">
+                  <text class="_icon-forward" />
                 </view>
               </view>
-              <!-- #endif -->
-            </view>
-            <view class="store-distance ss-flex ss-row-center" @tap.stop="showMaoLocation(item)">
-              <text class="addressTxt" v-if="item.distance">距离{{ item.distance.toFixed(2) }}千米</text>
-              <text class="addressTxt" v-else>查看地图</text>
+            </a>
+            <!-- #endif -->
+            <!-- #ifdef MP -->
+            <view class="store-phone" @click="call(item.phone)">
               <view class="iconfont">
                 <view class="ss-rest-button">
                   <text class="_icon-forward" />
                 </view>
               </view>
             </view>
+            <!-- #endif -->
+          </view>
+          <view class="store-distance ss-flex ss-row-center" @tap.stop="showMaoLocation(item)">
+            <text class="addressTxt" v-if="item.distance">
+              距离{{ item.distance.toFixed(2) }}千米
+            </text>
+            <text class="addressTxt" v-else>查看地图</text>
+            <view class="iconfont">
+              <view class="ss-rest-button">
+                <text class="_icon-forward" />
+              </view>
+            </view>
           </view>
         </view>
       </view>
@@ -78,7 +82,6 @@
     const jsWxSdk = sheep.$platform.useProvider('wechat').jsWxSdk;
     if (jsWxSdk.isWechat()) {
       jsWxSdk.getLocation((res) => {
-        console.log(res);
         state.user_latitude = res.latitude;
         state.user_longitude = res.longitude;
         uni.setStorageSync(LATITUDE, res.latitude);
@@ -95,7 +98,8 @@
             state.user_longitude = res.longitude;
             uni.setStorageSync(LATITUDE, res.latitude);
             uni.setStorageSync(LONGITUDE, res.longitude);
-          } catch {
+          } catch (e) {
+            console.error(e);
           }
           getList();
         },
@@ -115,7 +119,7 @@
         latitude: Number(e.latitude),
         longitude: Number(e.longitude),
         name: e.name,
-        address: `${e.areaName}-${e.detailAddress}`
+        address: `${e.areaName}-${e.detailAddress}`,
       });
     } else {
       // #endif
@@ -124,7 +128,7 @@
         longitude: Number(e.longitude),
         name: e.name,
         address: `${e.areaName}-${e.detailAddress}`,
-        success: function() {
+        success: function () {
           console.log('success');
         },
       });
@@ -175,7 +179,7 @@
       state.user_latitude = uni.getStorageSync(LATITUDE);
       state.user_longitude = uni.getStorageSync(LONGITUDE);
     } catch (e) {
-      // error
+      console.error(e);
     }
   });
 </script>
@@ -183,7 +187,7 @@
   .line1 {
     overflow: hidden;
     text-overflow: ellipsis;
-    white-space: nowrap
+    white-space: nowrap;
   }
 
   .geoPage {

+ 0 - 17
sheep/api/promotion/coupon.js

@@ -79,23 +79,6 @@ const CouponApi = {
       },
     });
   },
-  // 获得匹配指定商品的优惠劵列表
-  getMatchCouponList: (price, spuIds, skuIds, categoryIds) => {
-    return request({
-      url: '/promotion/coupon/match-list',
-      method: 'GET',
-      params: {
-        price,
-        spuIds: spuIds.join(','),
-        skuIds: skuIds.join(','),
-        categoryIds: categoryIds.join(','),
-      },
-      custom: {
-        showError: false,
-        showLoading: false, // 避免影响 settlementOrder 结算的结果
-      },
-    });
-  }
 };
 
 export default CouponApi;

+ 6 - 16
sheep/components/s-coupon-list/s-coupon-list.vue

@@ -37,30 +37,22 @@
         <view class="ss-flex ss-row-between ss-m-t-16">
           <view
             class="sellby-text"
-            :class=" isDisable ? 'disabled-color' : 'subtitle-color'"
+            :class="isDisable ? 'disabled-color' : 'subtitle-color'"
             v-if="data.validityType === 2"
           >
             有效期:领取后 {{ data.fixedEndTerm }} 天内可用
           </view>
-          <view
-            class="sellby-text"
-            :class=" isDisable ? 'disabled-color' : 'subtitle-color'"
-            v-else
-          >
+          <view class="sellby-text" :class="isDisable ? 'disabled-color' : 'subtitle-color'" v-else>
             有效期: {{ sheep.$helper.timeFormat(data.validStartTime, 'yyyy-mm-dd') }} 至
             {{ sheep.$helper.timeFormat(data.validEndTime, 'yyyy-mm-dd') }}
           </view>
-          <view
-            class="value-enough"
-            :class="isDisable ? 'disabled-color' : 'subtitle-color'"
-          >
+          <view class="value-enough" :class="isDisable ? 'disabled-color' : 'subtitle-color'">
             满 {{ fen2yuan(data.usePrice) }} 可用
           </view>
         </view>
       </view>
     </view>
 
-    <!-- TODO 芋艿:可优化,增加优惠劵的描述 -->
     <view class="desc ss-flex ss-row-between">
       <view>
         <view class="desc-title">{{ data.description }}</view>
@@ -76,17 +68,15 @@
 </template>
 
 <script setup>
-  import { computed, reactive } from 'vue';
+  import { computed } from 'vue';
   import { fen2yuan } from '../../hooks/useGoods';
   import sheep from '../../index';
 
-  const state = reactive({});
-
   const isDisable = computed(() => {
     if (props.type === 'coupon') {
       return false;
     }
-    return props.data.status !== 1;
+    return props.disabled;
   });
 
   // 接受参数
@@ -202,4 +192,4 @@
   .price-text {
     color: #ff0000;
   }
-</style>
+</style>

+ 16 - 12
sheep/components/s-coupon-select/s-coupon-select.vue

@@ -18,14 +18,11 @@
       >
         <!--可使用的优惠券区域-->
         <view class="subtitle ss-m-l-20">可使用优惠券</view>
-        <view v-for="(item, index) in state.couponInfo.filter(coupon => coupon.match)" :key="index">
+        <view
+          v-for="(item, index) in state.couponInfo.filter((coupon) => coupon.match)"
+          :key="index"
+        >
           <s-coupon-list :data="item" type="user" :disabled="false">
-            <template v-slot:reason>
-              <view class="ss-flex ss-m-t-24">
-                <view class="reason-title">可用原因:</view>
-                <view class="reason-desc">{{ item.description || '已达到使用门槛' }}</view>
-              </view>
-            </template>
             <template #default>
               <label class="ss-flex ss-col-center" @tap="radioChange(item.id)">
                 <radio
@@ -40,17 +37,16 @@
         </view>
         <!--不可使用的优惠券区域-->
         <view class="subtitle ss-m-t-40 ss-m-l-20">不可使用优惠券</view>
-        <view v-for="item in state.couponInfo.filter(coupon => !coupon.match)" :key="item.id">
+        <view v-for="item in state.couponInfo.filter((coupon) => !coupon.match)" :key="item.id">
           <s-coupon-list :data="item" type="user" :disabled="true">
             <template v-slot:reason>
               <view class="ss-flex ss-m-t-24">
                 <view class="reason-title"> 不可用原因:</view>
-                <view class="reason-desc">{{ item.description || '未达到使用门槛' }}</view>
+                <view class="reason-desc">{{ item.mismatchReason || '未达到使用门槛' }}</view>
               </view>
             </template>
           </s-coupon-list>
         </view>
-     
       </scroll-view>
     </view>
     <view class="modal-footer ss-flex">
@@ -62,7 +58,8 @@
   import { computed, reactive } from 'vue';
 
   const props = defineProps({
-    modelValue: { // 优惠劵列表
+    modelValue: {
+      // 优惠劵列表
       type: Object,
       default() {},
     },
@@ -91,7 +88,7 @@
   // 确认优惠劵
   const onConfirm = () => {
     emits('confirm', state.couponId);
-  }
+  };
 </script>
 <style lang="scss" scoped>
   :deep() {
@@ -103,25 +100,30 @@
   .model-box {
     height: 60vh;
   }
+
   .title {
     font-size: 36rpx;
     height: 80rpx;
     font-weight: bold;
     color: #333333;
   }
+
   .subtitle {
     font-size: 26rpx;
     font-weight: 500;
     color: #333333;
   }
+
   .model-content {
     height: 54vh;
   }
+
   .modal-footer {
     width: 100%;
     height: 120rpx;
     background: #fff;
   }
+
   .confirm-btn {
     width: 710rpx;
     margin-left: 20rpx;
@@ -130,12 +132,14 @@
     border-radius: 40rpx;
     color: #fff;
   }
+
   .reason-title {
     font-weight: 600;
     font-size: 20rpx;
     line-height: 26rpx;
     color: #ff0003;
   }
+
   .reason-desc {
     font-weight: 600;
     font-size: 20rpx;