Преглед изворни кода

feat(KIP-12589): Temp parking frontend | BKC |新会员积分联调

john пре 1 година
родитељ
комит
1f9bd81520

+ 71 - 0
src/api/mockData/checkout.bj1.response.json

@@ -0,0 +1,71 @@
+{
+  "parkingRecord": {
+    "vehicleNo": "浙C35210",
+    "enterTime": "2023-10-17 09:13:52",
+    "serviceMin": 3015,
+    "totalFee": 3016,
+    "actualPayFee": 0.0,
+    "thirdParkOrderNo": "50E19852-2E31-4FFE-B526-662FFF9C5678",
+    "createdByQrCode": false,
+    "totalFeeInYuan": 30.16
+  },
+  "discountInfo": {
+    "usingTotalDiscount": 40,
+    "memberLevelDiscount": false,
+    "newMemberPoints": {
+      "available": 2400,
+      "totalAvailable": 2700,
+      "maxDiscountHours": 5,
+      "pointsPerUnit": 300,
+      "newMember": true,
+      "label": "已选择兑换1小时",
+      "usedDiscountHours": 4,
+      "discountFee": 10
+    },
+    "points": [
+      {
+        "available": 800,
+        "maxDiscountFee": 20,
+        "pointsPerUnit": 800,
+        "unitAmount": 10,
+        "totalAvailable": 2700, 
+        "unitHour": 1,
+        "newMember": false,
+        "label": "已选择兑换2小时",
+        "discountFee": 20
+      }
+    ],
+    "coupons": [
+      {
+        "code": "nxlrr9w4mzm_t",
+        "couponId": "f751bded055f48fa888fe5e516894f13",
+        "status": "available",
+        "name": "工作日停车券",
+        "expirationDate": "2022-02-16 15:38:00",
+        "discountFee": 10,
+        "defaultSelected": true,
+        "superposition": "2",
+        "limitCountPerOrder": 2
+      }
+    ]
+  },
+  "parkingRule": {
+    "enableNewMemberPoints": true,
+    "enablePoints": true,
+    "unLimitWeekendPoints": false,
+    "enableCoupon": true,
+    "enablePaperCoupons": false,
+    "enableConsume": false,
+    "enableConsumeNonSplit": true,
+    "availableDiscountFee": 20,
+    "hourPrice": 10,
+    "oneTimeLimitation": false,
+    "oneDayLimitation": false
+  },
+  "parkInfo": {
+    "parkName": "北京嘉里中心停车场",
+    "description": "计费基础规则:15分钟内免费,首小时15元,其后每小时5元,全天封顶60元。\n嘉湾汇会员停车礼遇:\n银卡:每月可免费领取2张首2小时停车券\n金卡:每月可免费领取5张首2小时停车券\n铂金卡:每月可免费领取10张首2小时停车券\n*数量有限,领完即止\n仅限开具一个月内的停车费电子发票 ",
+    "parkMallCode": 3,
+    "buildingId": "BKC-P1"
+  }
+}

+ 293 - 0
src/components/newMemberPoints/index.vue

@@ -0,0 +1,293 @@
+<template>
+  <van-popup
+    v-model="popup"
+    position="bottom"
+    :animation="false"
+    :maskClick="false"
+    :close-on-click-overlay="false"
+  >
+    <div class="popue_box" v-if="orderDetail && orderDetail.discountInfo">
+      <div class="popue_box_index1">积分减免</div>
+      <div class="popue_box_index">
+        <div>减免规则</div>
+        <div style="color: #989898">{{ newMemberPoints.pointsPerUnit }}积分抵扣1小时</div>
+      </div>
+      <div class="popue_box_index">
+        <div>可用积分</div>
+        <div style="color: #999999">{{ newMemberPointsAvailable }}分</div>
+      </div>
+      <div class="popue_box_index">
+        <div>抵扣时长</div>
+        <div class="popue_box_index" style="width: 335px">
+          <div class="popue_box_index4_xs van-hairline--surround">
+            <div class="popue_box_index4_xs_index1" @click="pointsMath('minus')">
+              -
+            </div>
+            <div class="popue_box_index4_xs_index2">{{ pointsTime }}</div>
+            <div class="popue_box_index4_xs_index3" @click="pointsMath('add')">
+              +
+            </div>
+          </div>
+          <div style="color: #808080">
+            小时
+          </div>
+        </div>
+      </div>
+      <div class="popue_box_index5">
+        <div
+          class="popue_box_index4_by"
+          @click="cancelPointsMathPopup()"
+        >
+          取消
+        </div>
+        <div
+          class="popue_box_index4_by1"
+          @click="savePointsMathPopup()"
+        >
+          确定
+        </div>
+      </div>
+      <van-number-keyboard safe-area-inset-bottom/>
+    </div>
+  </van-popup>
+</template>
+<script>
+import {mapState} from "vuex";
+import {Toast} from "vant";
+
+
+export default {
+  name: 'newMemberPointsIndex',
+  computed:{
+    ...mapState({
+      orderDetail: (state) => state.order.orderDetail,
+    }),
+    parkingRule() {
+      if(!this.orderDetail?.parkingRule) {
+        return  {}
+      }
+      return this.orderDetail.parkingRule
+    },
+    newMemberPoints () {
+      return this.orderDetail.discountInfo.newMemberPoints
+    },
+    // points () {
+    //   if(!this.orderDetail?.discountInfo?.points || !this.orderDetail.discountInfo?.points?.length) {
+    //     return
+    //   } 
+    //   return this.orderDetail.discountInfo.points[0]
+    // },
+    // pointsTime() {
+    //   if(!this.newMemberPoints?.discountFee) return 0
+    //
+    //   this.newMemberPoints?.discountFee
+    // },
+    hourPrice() {
+      return this.parkingRule.hourPrice
+    },
+  },
+  data() {
+    return {
+      popup: false,
+      pointsTime: 0,
+      available: 0,
+      newMemberPointsAvailable: 0
+    }
+  },
+  methods:{
+    open () {
+      if ( this?.newMemberPoints?.discountFee ) {
+        this.pointsTime = this?.newMemberPoints?.discountFee / this.hourPrice
+      }
+      this.newMemberPointsAvailable = this.newMemberPoints.available // 新会员积分
+      this.available = this.orderDetail.discountInfo.points[0].available // 积分
+      this.popup = true
+    },
+    pointsMath(type) {
+      const {usedDiscountHours, maxDiscountHours} = this.newMemberPoints
+      if ( type === 'minus' && this.pointsTime ) {
+        this.pointsTime = this.pointsTime - 1;
+        this.newMemberPointsAvailable = this.newMemberPointsAvailable + this.newMemberPoints.pointsPerUnit;
+        return
+      }
+      // 可能还有隐藏上限,就是普通的points的使用,单次不能超过上限
+      if(type === 'add' && this.newMemberPointsAvailable > this.newMemberPoints.pointsPerUnit && (this.pointsTime + usedDiscountHours < maxDiscountHours)) {
+        this.pointsTime = this.pointsTime + 1
+        this.newMemberPointsAvailable = this.newMemberPointsAvailable - this.newMemberPoints.pointsPerUnit
+      } else {
+        Toast('当前优惠已达上限')
+      }
+      // 调整当前积分
+      // 调整points的积分available
+    },
+    cancelPointsMathPopup() {
+      this.popup = false
+    },
+    savePointsMathPopup() {
+      // 如果是重复提交的话
+      if(this.newMemberPoints.available === this.newMemberPointsAvailable) {
+        this.popup = false;
+        return
+      }
+      this.$store.dispatch('order/saveNewMemberPointsMath', {
+        newMemberPoints: {
+          ...this.newMemberPoints,
+          selected: this.pointsTime > 0,
+          discountFee: this.pointsTime > 0 ? this.pointsTime * this.hourPrice : 0,
+          "available": this.newMemberPointsAvailable,
+        },
+        callback: () => {
+          this.popup = false;
+        }
+      });
+    },
+  }
+}
+</script>
+
+<style scoped lang="less">
+/*积分*/
+.popue_box {
+  height: 695px;
+  background-color: #fff;
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+
+  .popue_box_index {
+    width: 92%;
+    margin-left: 4%;
+    height: 117px;
+    border-bottom: 1px solid #f5f5f5;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    font-family: 'PingFang SC';
+    font-style: normal;
+    font-weight: 400;
+    font-size: 34px;
+    text-align: right;
+    color: #333333;
+  }
+
+  .popue_box_index1 {
+    width: 92%;
+    font-size: 34px;
+    margin-left: 4%;
+    font-weight: 700;
+    height: 117px;
+    line-height: 117px;
+    border-bottom: 1px solid #f5f5f5;
+    text-align: center;
+  }
+
+  .popue_box_index4_xs {
+    width: 260px;
+    height: 72px;
+    border: 2px solid #D8DAE0;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    border-radius: 10px;
+
+    .popue_box_index4_xs_index1 {
+      width: 72px;
+      height: 72px;
+      background-color: #FAFBFF;
+      text-align: center;
+      line-height: 72px;
+      border-right: 1px solid #e5e6ec;
+    }
+
+    .popue_box_index4_xs_index2 {
+      width: 116px;
+      height: 72px;
+      line-height: 72px;
+      text-align: center;
+      background-color: #FFFFFF;
+    }
+
+    .popue_box_index4_xs_index3 {
+      width: 72px;
+      height: 72px;
+      background-color: #f5f8fb;
+      text-align: center;
+      line-height: 72px;
+      border-left: 1px solid #e5e6ec;
+    }
+  }
+
+  .popue_box_index5 {
+    font-size: 30px;
+    width: 92%;
+    margin-left: 4%;
+    font-weight: 700;
+    height: 214px;
+    line-height: 90px;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+  }
+
+  .popue_box_index4_by {
+    width: 320px;
+    height: 90px;
+    line-height: 90px;
+    color: #fff;
+    border-radius: 60px;
+    text-align: center;
+    color: var(--k-color-primary-01, #064c8a);
+    font-weight: 700;
+    border: 1px solid var(--k-color-primary-01, #064c8a);
+  }
+
+  .blue_popue_box_index4_by {
+    .color_popue_box_index4_by('blue');
+  }
+
+  .green_popue_box_index4_by {
+    .color_popue_box_index4_by('green');
+  }
+
+  .color_popue_box_index4_by(@value) {
+    @color: 'color-@{value}';
+    color: @@color;
+    border: 1px solid @@color;
+  }
+
+  .popue_box_index4_by1 {
+    width: 320px;
+    height: 90px;
+    line-height: 90px;
+    color: #fff;
+    border-radius: 60px;
+    text-align: center;
+    // background-image: linear-gradient(to right, #7e4fa1, #433c7f);
+    background-color: var(--k-color-primary-01, #064c8a);
+    border: 1px solid var(--k-color-primary-01, #064c8a);
+  }
+}
+.popue_box_index4_by {
+  width: 320px;
+  height: 90px;
+  line-height: 90px;
+  color: #fff;
+  border-radius: 60px;
+  text-align: center;
+  color: var(--k-color-primary-01, #064c8a);
+  font-weight: 700;
+  border: 1px solid var(--k-color-primary-01, #064c8a);
+}
+.popue_box_index4_by1 {
+  width: 320px;
+  height: 90px;
+  line-height: 90px;
+  color: #fff;
+  border-radius: 60px;
+  text-align: center;
+  // background-image: linear-gradient(to right, #7e4fa1, #433c7f);
+  background-color: var(--k-color-primary-01, #064c8a);
+  border: 1px solid var(--k-color-primary-01, #064c8a);
+}
+</style>

+ 123 - 0
src/components/newMemberPoints/item.vue

@@ -0,0 +1,123 @@
+<template>
+  <div class="info-item-box" v-if="enablePoints">
+    <div class="label">新会员积分优惠</div>
+    <div :class="['value']" @click="showPointsMathPopup('bottom')">
+      <span :class="[integralDesc === '今日已达上限' ? 'text-disable' : 'text-red']">{{ integralDesc }}</span>
+      <van-icon name="arrow"/>
+    </div>
+    <newMemberPoints :key="newMemberPointsKey" ref="newMemberPoints"></newMemberPoints>
+  </div>
+</template>
+<script>
+import newMemberPoints from "@/components/newMemberPoints/index.vue";
+import {mapState} from "vuex";
+import {Toast} from "vant";
+
+export default {
+  name: 'newMemberPointsItem',
+  components: {newMemberPoints},
+  data() {
+    return {
+      newMemberPointsKey: '1235'
+      // enablePoints: true
+    }
+  },
+  computed: {
+    ...mapState({
+      orderDetail: (state) => state.order.orderDetail,
+    }),
+    enablePoints() {
+      // console.log(31, this.orderDetail?.discountInfo?.newMemberPoints)
+      return this.orderDetail?.discountInfo?.newMemberPoints && this.orderDetail?.discountInfo?.newMemberPoints.newMember 
+    },
+    integralDesc() {
+      if(!this.enablePoints) {
+        return ''
+      }
+      const { maxDiscountHours, usedDiscountHours, discountFee = 0, available = 0,pointsPerUnit = 0 } = this.orderDetail?.discountInfo?.newMemberPoints
+      const { hourPrice = 0 } = this.orderDetail?.parkingRule
+      /*
+      *       "available": 2400,
+      "totalAvailable": 2700,
+      "maxDiscountHours": 5,
+      "pointsPerUnit": 300,
+      "newMember": true,
+      "label": "已选择兑换1小时",
+      "usedDiscountHours": 4,
+      "discountFee": 10*/
+      if (discountFee > 0) {
+        return `已选择兑换${discountFee / hourPrice }小时`;
+      }
+      if (available < pointsPerUnit) {
+        return `${pointsPerUnit}积分可停车1小时`;
+      }
+      return `${available}积分可减免`;
+    },
+  },
+  methods: {
+    showPointsMathPopup() {
+      if(this.integralDesc === '今日已达上限') {
+        Toast('今日已达上限')
+        return
+      }
+      this.$refs['newMemberPoints'].open()
+      // this.newMemberPointsKey = new Date().getTime()
+      // setTimeout(() => {
+      //   this.$refs['newMemberPoints'].open()
+      // }, 10)
+    },
+  }
+
+}
+</script>
+<style scoped lang="less">
+.info-item-box {
+  display: flex;
+  justify-content: space-between;
+  padding-bottom: 30px;
+  &.npb{
+    padding-bottom: 0;
+  }
+  .label {
+    padding-left: 36px;
+    //padding-bottom: 39px;
+    text-align: left;
+
+    font-family: 'PingFang SC';
+    font-style: normal;
+    font-weight: 400;
+    font-size: 30px;
+    color: #999999;
+
+  }
+
+  .value {
+    text-align: right;
+    padding-right: 36px;
+    font-family: 'PingFang SC';
+    font-style: normal;
+    font-weight: 400;
+    font-size: 30px;
+    color: #333333;
+    .van-icon {
+      color: #999999;
+    }
+
+    &.bold-fz {
+      font-family: 'PingFang SC';
+      font-style: normal;
+      font-weight: 500;
+      font-size: 34px;
+      color: #333333;
+    }
+    .text-red {
+      color: #F24439;
+    }
+
+    .text-disable {
+      color: #999;
+    }
+  }
+}
+
+</style>

+ 16 - 3
src/pages/parkingFeeV2/mixins/parkingFeeDetail.js

@@ -10,11 +10,11 @@ import { Dialog, Toast } from 'vant';
 import { ordersAndPrepay } from '@/api/parking';
 import store from "@/store";
 // import newMemberPoints from '@/components/newMemberPoints/index.vue'
-// import newMemberPointsItem from '@/components/newMemberPoints/item.vue'
+import newMemberPointsItem from '@/components/newMemberPoints/item.vue'
 
 export default {
   name: 'parkingFeeDetail',
-  // components: { newMemberPoints, newMemberPointsItem },
+  components: { newMemberPointsItem },
   data() {
     this.toPay = debounce(this.toPay, 5000, {
       leading: true,
@@ -253,7 +253,7 @@ export default {
         }
       }, 10000)
       const { parkingRecord, discountInfo = {}, parkingRule = {}} = this.orderDetail;
-      const { coupons, points, memberGrade = [], paperCoupons = [], consume = [] } = discountInfo
+      const { coupons, points, memberGrade = [], paperCoupons = [], consume = [], newMemberPoints= {} } = discountInfo
       const { hourPrice } = parkingRule
       try {
         const params = {
@@ -345,6 +345,19 @@ export default {
               }
             })
          }
+        // 新会员积分, 默认带上了,然后不加也不影响
+        // if ( newMemberPoints?.discountFee ) {
+        //   params.discountInfo.paperCoupons = paperCoupons.filter(elm => {
+        //     if ( !elm.discountFee ) {
+        //       return false
+        //     }
+        //     return {
+        //       ...elm,
+        //       "discountFee": elm.discountFee,
+        //       // discountTime: elm.discountFee / hourPrice * 60
+        //     }
+        //   })
+        // }
         console.log('下单时的参数', params);
         const unlicensed = this.$route.query?.vehicleNo ? this.$route.query?.vehicleNo.indexOf('临') > -1 : false; // true: 临时车牌;false:燃油车牌
         const res = await ordersAndPrepay(params, unlicensed);

+ 2 - 0
src/pages/parkingFeeV2/parkingFeeDetail.vue

@@ -35,6 +35,8 @@
             <van-icon name="arrow"/>
           </div>
         </div>
+        <!-- 新会员积分 -->
+        <newMemberPointsItem></newMemberPointsItem>
         <div class="info-item-box" v-if="enablePoints">
           <div class="label">积分减免</div>
           <div :class="['value']" @click="showPointsMathPopup('bottom')">

+ 1 - 1
src/store/order/coupon.js

@@ -44,7 +44,7 @@ export default {
   async saveCouponMath( {commit,dispatch,state},{couponList,callback} ) {
     const orderDetail = {...state.orderDetail};
     orderDetail.discountInfo.coupons = couponList;
-    setSelected(['paperCoupons','consume','points','memberGrade'],orderDetail)
+    setSelected(['paperCoupons','consume','points','memberGrade','newMemberPoints'],orderDetail)
     try {
       const res = await calculateDiscount({
         ...orderDetail,

+ 1 - 1
src/store/order/index.js

@@ -1,4 +1,4 @@
-import checkOutQHResponse from "@/api/mockData/checkout.pd14.response.json";
+import checkOutQHResponse from "@/api/mockData/checkout.bj1.response.json";
 import { checkOut,calculateDiscount,ordersAndPrepay,currentUnlicensedPlate,unlicensedCarCheckIn,unlicensedCarCheckout } from '@/api/parking';
 import state from "@/store/order/state";
 import mutations from "@/store/order/mutations";

+ 1 - 1
src/store/order/memberLevel.js

@@ -60,7 +60,7 @@ export default {
   },
   async saveDiscounts( {commit,dispatch},{orderDetail,callback} ) {
     try {
-      setSelected(['paperCoupons','coupons','points',],orderDetail)
+      setSelected(['paperCoupons','coupons','points','newMemberPoints'],orderDetail)
       const res = await calculateDiscount({
         ...orderDetail,
       });

+ 1 - 1
src/store/order/paperCoupon.js

@@ -37,7 +37,7 @@ export default {
   async savePaperCoupon( {commit,dispatch,state},{paperCoupons,callback} ) {
     try {
       const orderDetail = {...state.orderDetail};
-      setSelected(['coupons','consume','points','memberGrade'], orderDetail)
+      setSelected(['coupons','consume','points','memberGrade','newMemberPoints'], orderDetail)
       if (!orderDetail?.discountInfo?.paperCoupons) {
         orderDetail.discountInfo =  {
           paperCoupons: []

+ 17 - 2
src/store/order/points.js

@@ -1,6 +1,7 @@
 import { checkOut,calculateDiscount,ordersAndPrepay,currentUnlicensedPlate,unlicensedCarCheckIn,unlicensedCarCheckout } from '@/api/parking';
 import { setSelected } from './utils'
 import {Toast} from "vant";
+import lodash from 'lodash'
 
 export default {
 
@@ -242,7 +243,7 @@ export default {
         return
       }
       // 如果是会员等级减免\如果是消费减免\如果是纸质优惠券\电子券的话
-      setSelected(['memberGrade','consume','paperCoupons','coupons'],orderDetail)
+      setSelected(['memberGrade','consume','paperCoupons','coupons','newMemberPoints'],orderDetail)
       // 计算积分修改之后的金额,返回给后端
       // orderDetail.discountInfo.points[0].discountFee = state.pointsTime * orderDetail.discountInfo.points[0].unitAmount;
       orderDetail.discountInfo.points[0].discountFee = parkMallCode === 5 ? state.pointsTime : state.pointsTime * orderDetail.discountInfo.points[0].unitAmount;
@@ -268,7 +269,21 @@ export default {
     }
     //
   },
-
+  async saveNewMemberPointsMath({commit,dispatch,state},{
+    newMemberPoints,
+    callback
+  }) {
+    const orderDetail = lodash.cloneDeep(state.orderDetail)
+    orderDetail.discountInfo.newMemberPoints = newMemberPoints;
+    setSelected(['memberGrade','consume','paperCoupons','coupons','points'],orderDetail)
+    // 新会员积分
+    const res = await calculateDiscount({
+      ...orderDetail,
+    });
+    console.log('新会员积分修改结果  ',{res});
+    dispatch('orderInitRule',res);
+    callback && callback();
+  },
   getIntegralDesc() {
     // 自动勾选积分优惠
     // 深圳是最大抵扣金额

+ 9 - 0
src/store/order/utils.js

@@ -61,6 +61,15 @@ export function setSelected( types,orderDetail ) {
           })
         }
         break
+      case 'newMemberPoints':
+        // 如果是新会员积分
+        if ( orderDetail.discountInfo?.newMemberPoints?.newMember ) {
+          orderDetail.discountInfo.newMemberPoints = {
+            ...orderDetail.discountInfo.newMemberPoints,
+            selected: orderDetail.discountInfo.newMemberPoints.hasOwnProperty('selected') ? orderDetail.discountInfo.newMemberPoints.selected : orderDetail.discountInfo.newMemberPoints?.discountFee > 0 || false
+          }
+        }
+        break
     }
   }