Просмотр исходного кода

花掌柜-小程序、收银台 开单优惠折扣金额计算

ouyang 8 часов назад
Родитель
Сommit
33bff0203b
3 измененных файлов с 353 добавлено и 15 удалено
  1. 88 7
      hdApp/src/admin/billing/affirm.vue
  2. 6 0
      hdPad/src/pages/home/cash.vue
  3. 259 8
      hdPad/src/pages/home/components/settlePop.vue

+ 88 - 7
hdApp/src/admin/billing/affirm.vue

@@ -295,18 +295,27 @@
             </view>
             </view>
             <text style="color: #3385FF;width:170upx;">¥{{parseFloat(systemPrice)}}</text>
             <text style="color: #3385FF;width:170upx;">¥{{parseFloat(systemPrice)}}</text>
             <button @tap="showDiscount()" class="admin-button-com middle default" style="width:140upx;">打折</button>
             <button @tap="showDiscount()" class="admin-button-com middle default" style="width:140upx;">打折</button>
-            <text v-if="discountValue>0 && discountValue<1">{{ (Number(discountValue)*10).toFixed(1) }}折</text>
+            <text v-if="discountValue>0 && discountValue<1" class="manual-discount-tag">{{ (Number(discountValue)*10).toFixed(1) }}折</text>
           </tui-list-cell>
           </tui-list-cell>
 
 
           <tui-list-cell class="line-cell" :hover="false" :arrow="false" >
           <tui-list-cell class="line-cell" :hover="false" :arrow="false" >
             <view v-if="form.hasPay == 2" class="tui-title">应收金额</view>
             <view v-if="form.hasPay == 2" class="tui-title">应收金额</view>
             <view v-else-if="form.hasPay == 3" class="tui-title">余额扣减</view>
             <view v-else-if="form.hasPay == 3" class="tui-title">余额扣减</view>
             <view v-else class="tui-title">实际金额</view>
             <view v-else class="tui-title">实际金额</view>
-            <input style="border:1upx solid #eee;color:#3385FF;width:150upx;height:70upx;" type="digit" @focus="modifyPrice=''" v-model="modifyPrice" placeholder-class="tui-placeholder"/>
-            <!-- 有会员折扣/门店满减时右侧展示具体优惠;人工加价仍显示包装费;其它降价显示通用优惠 -->
-            <text v-if="modifyPrice > 0 && modifyPrice > systemPrice" style="font-size:25upx;margin-left:20upx;color:red;">人工包装费 ¥{{parseFloat((modifyPrice-systemPrice).toFixed(2))}}</text>
-            <text v-else-if="wholeDiscountLabel" style="font-size:25upx;margin-left:20upx;color:#ff2842;">{{ wholeDiscountLabel }} {{ wholeDiscountAmountText }}</text>
-            <text v-else-if="modifyPrice > 0 && modifyPrice < systemPrice" style="font-size:25upx;margin-left:20upx;color:green;">优惠 ¥{{parseFloat((systemPrice-modifyPrice).toFixed(2))}}</text>
+            <input class="modify-price-input" type="digit" @focus="modifyPrice=''" v-model="modifyPrice" placeholder-class="tui-placeholder"/>
+            <!-- 实际金额右侧优惠标签:用色块把会员折扣/满减/人工降价从输入框拉开,避免店员漏看 -->
+            <view v-if="modifyPrice > 0 && modifyPrice > systemPrice" class="price-hint-tag pack">
+              <text class="price-hint-label">人工包装费</text>
+              <text class="price-hint-amount">¥{{parseFloat((modifyPrice-systemPrice).toFixed(2))}}</text>
+            </view>
+            <view v-else-if="wholeDiscountLabel" class="price-hint-tag discount">
+              <text class="price-hint-label">{{ wholeDiscountLabel }}</text>
+              <text class="price-hint-amount">{{ wholeDiscountAmountText }}</text>
+            </view>
+            <view v-else-if="modifyPrice > 0 && modifyPrice < systemPrice" class="price-hint-tag discount">
+              <text class="price-hint-label">优惠</text>
+              <text class="price-hint-amount">¥{{parseFloat((systemPrice-modifyPrice).toFixed(2))}}</text>
+            </view>
           </tui-list-cell>
           </tui-list-cell>
 
 
 				<tui-list-cell class="line-cell" :hover="false" :arrow="true">
 				<tui-list-cell class="line-cell" :hover="false" :arrow="true">
@@ -521,6 +530,7 @@ import { mapActions, mapGetters } from "vuex";
 import { getCustomInfo} from "@/api/custom"
 import { getCustomInfo} from "@/api/custom"
 import { quickOrderAllDeliveryQuotes } from '@/api/express/delivery'
 import { quickOrderAllDeliveryQuotes } from '@/api/express/delivery'
 import { getAvailableHb } from "@/api/hb"
 import { getAvailableHb } from "@/api/hb"
+import { currentShop as fetchCurrentShop } from '@/api/shop'
 import ModalModule from "@/components/plugin/modal"
 import ModalModule from "@/components/plugin/modal"
 import MxDatePicker from '@/components/mx-datepicker/mx-datepicker.vue';
 import MxDatePicker from '@/components/mx-datepicker/mx-datepicker.vue';
 import TimePicker from '@/components/plugin/TimePicker';
 import TimePicker from '@/components/plugin/TimePicker';
@@ -633,7 +643,8 @@ export default {
     let that = this
     let that = this
     this.initMerchantInfo().then((data) => {
     this.initMerchantInfo().then((data) => {
         uni.setNavigationBarTitle({ title: data.name })
         uni.setNavigationBarTitle({ title: data.name })
-        that.currentShop = data.shopInfo
+        // merchant/detail 只有商户/跑腿字段,没有 shopInfo 和满减配置;先用登录态门店兜底
+        that.currentShop = (that.getMyShopInfo && that.getMyShopInfo.shop) || {}
         that.openIntraCity = data.openIntraCity
         that.openIntraCity = data.openIntraCity
         that.hcFreeKm = data.hcFreeKm
         that.hcFreeKm = data.hcFreeKm
         try {
         try {
@@ -647,6 +658,8 @@ export default {
         } catch (e) {
         } catch (e) {
            that.hsAddFee = 0
            that.hsAddFee = 0
         }
         }
+        // 再拉当前门店,确保 meetNum/meetAmount/cutAmount/cutStyle 最新,互斥优惠才能算门店满减
+        that.loadCurrentShopForDiscount()
     })
     })
 
 
     if(Number(option.customId) > 0){
     if(Number(option.customId) > 0){
@@ -770,6 +783,10 @@ export default {
         this.syncModifyPriceWithWholeDiscount(this.systemPrice)
         this.syncModifyPriceWithWholeDiscount(this.systemPrice)
       },
       },
       deep: true
       deep: true
+    },
+    // 扎数变化可能只影响满减门槛,金额不变时也要重算互斥优惠
+    'allCount.bigLength'() {
+      this.syncModifyPriceWithWholeDiscount(this.systemPrice)
     }
     }
   },
   },
   computed: {
   computed: {
@@ -858,6 +875,18 @@ export default {
   methods: {
   methods: {
     init () {},
     init () {},
     ...mapActions(["initMerchantInfo"]),
     ...mapActions(["initMerchantInfo"]),
+    /**
+     * 拉取当前门店满减配置(meetNum/meetAmount/cutAmount/cutStyle)。
+     * 原因:initMerchantInfo 走 /merchant/detail,不含门店满减字段,会导致 shopSave 恒为 0、只剩会员折扣。
+     */
+    loadCurrentShopForDiscount() {
+      return fetchCurrentShop().then(res => {
+        if (res.code == 1 && res.data) {
+          this.currentShop = res.data
+          this.syncModifyPriceWithWholeDiscount(this.systemPrice)
+        }
+      }).catch(() => {})
+    },
     /**
     /**
      * 回写默认实际金额:
      * 回写默认实际金额:
      * - 已手动选打折/不打折:systemPrice * discountValue(不打折时为 1,即原价)
      * - 已手动选打折/不打折:systemPrice * discountValue(不打折时为 1,即原价)
@@ -2165,4 +2194,56 @@ export default {
         margin-top: 6upx;
         margin-top: 6upx;
     }
     }
 }
 }
+
+/* 合计金额旁手选折扣:红色加粗,和实际金额优惠标签同一套强调色 */
+.manual-discount-tag {
+  margin-left: 16upx;
+  color: #ff2842;
+  font-size: 30upx;
+  font-weight: bold;
+}
+
+/* 实际金额输入框:固定宽度,把右侧空间留给优惠标签 */
+.modify-price-input {
+  border: 1upx solid #eee;
+  color: #3385FF;
+  width: 150upx;
+  height: 70upx;
+  flex-shrink: 0;
+}
+
+/* 实际金额右侧优惠/加价标签:红底白字两行,店员一眼能看到优惠类型和金额 */
+.price-hint-tag {
+  margin-left: 16upx;
+  padding: 8upx 16upx;
+  border-radius: 8upx;
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+  justify-content: center;
+  flex-shrink: 1;
+  min-width: 0;
+
+  .price-hint-label {
+    font-size: 22upx;
+    color: #fff;
+    line-height: 1.2;
+  }
+
+  .price-hint-amount {
+    margin-top: 4upx;
+    font-size: 32upx;
+    font-weight: bold;
+    color: #fff;
+    line-height: 1.2;
+  }
+
+  &.discount {
+    background-color: #ff2842;
+  }
+
+  &.pack {
+    background-color: #ff6b35;
+  }
+}
 </style>
 </style>

+ 6 - 0
hdPad/src/pages/home/cash.vue

@@ -177,6 +177,7 @@ export default {
 			this.customId = shop && shop.defaultCustomId && shop.defaultCustomId > 0 ? Number(shop.defaultCustomId):0
 			this.customId = shop && shop.defaultCustomId && shop.defaultCustomId > 0 ? Number(shop.defaultCustomId):0
 			this.customName = '快捷开单'
 			this.customName = '快捷开单'
 			this.balance = 0
 			this.balance = 0
+			this.getDefaultCustomId(this.customId)
 			this.$refs.rightItemRef.renewMyRightItem(this.customId)
 			this.$refs.rightItemRef.renewMyRightItem(this.customId)
 			this.beginRemind()
 			this.beginRemind()
 		},
 		},
@@ -198,6 +199,7 @@ export default {
 		},
 		},
 		getDefaultCustomId(defaultCustomId){
 		getDefaultCustomId(defaultCustomId){
 			if(Number(defaultCustomId) > 0){
 			if(Number(defaultCustomId) > 0){
+				// 快捷开单/选客后都走这里,补齐客户折扣和地址给结算弹窗用
 				getDetail({userId:defaultCustomId}).then(res=>{
 				getDetail({userId:defaultCustomId}).then(res=>{
 					if(res.code == 1){
 					if(res.code == 1){
 						this.custom = res.data ? res.data : {}
 						this.custom = res.data ? res.data : {}
@@ -216,6 +218,9 @@ export default {
 			this.customId = Number(info.id)
 			this.customId = Number(info.id)
 			this.customName = info.name
 			this.customName = info.name
 			this.balance = Number(info.balance)>0 ? Number(info.balance) : 0
 			this.balance = Number(info.balance)>0 ? Number(info.balance) : 0
+			this.custom = info || {}
+			// 选客后拉详情,补齐 discount/地址,结算弹窗才能算会员折扣
+			this.getDefaultCustomId(this.customId)
 			this.$refs.rightItemRef.renewMyRightItem(this.customId)
 			this.$refs.rightItemRef.renewMyRightItem(this.customId)
 			this.beginRemind()
 			this.beginRemind()
 		},
 		},
@@ -234,6 +239,7 @@ export default {
 			this.customId = shop && shop.defaultCustomId && shop.defaultCustomId > 0 ? Number(shop.defaultCustomId):0
 			this.customId = shop && shop.defaultCustomId && shop.defaultCustomId > 0 ? Number(shop.defaultCustomId):0
 			this.customName = '快捷开单'
 			this.customName = '快捷开单'
 			this.balance = 0
 			this.balance = 0
+			this.getDefaultCustomId(this.customId)
 			//要调用rightItemRef里的方法更新,不能这边直接请求product.js里方法更新,因为会造成扫码那块出问题,识别不到,关键词hzg_scan_right_item
 			//要调用rightItemRef里的方法更新,不能这边直接请求product.js里方法更新,因为会造成扫码那块出问题,识别不到,关键词hzg_scan_right_item
 			this.$refs.rightItemRef.renewMyRightItem(this.customId)
 			this.$refs.rightItemRef.renewMyRightItem(this.customId)
 			this.getCustomData()
 			this.getCustomData()

+ 259 - 8
hdPad/src/pages/home/components/settlePop.vue

@@ -216,10 +216,16 @@
                 <text><text>{{totalPrice}}</text></text>
                 <text><text>{{totalPrice}}</text></text>
             </view>
             </view>
 
 
-            <view class="input-list" @click.stop="changeCheck(0)">
-                <text style="color:green;">应付金额</text>
-                <text style="font-size: 10upx;color:green;" v-if="diffPrice > 0">优惠¥<text>{{diffPrice}}</text></text>
-                <text><text :class="{selected:checkType == 0}">{{form.modifyPrice}}</text></text>
+            <view class="input-list payable-row" @click.stop="changeCheck(0)">
+                <text class="payable-label" style="color:green;">应付金额</text>
+                <!-- 会员折扣/门店满减优先;优惠文案居中展示,避免挤在左侧不好认 -->
+                <view class="payable-discount">
+                    <view v-if="wholeDiscountLabel" class="price-hint-tag">
+                        <text class="price-hint-text">{{ wholeDiscountLabel }} {{ wholeDiscountAmountText }}</text>
+                    </view>
+                    <text v-else-if="diffPrice > 0" class="generic-save-text">优惠¥{{diffPrice}}</text>
+                </view>
+                <text class="payable-price"><text :class="{selected:checkType == 0}">{{form.modifyPrice}}</text></text>
             </view>
             </view>
 
 
             <view class="keyboard-body_box"> <VKeyboard ref="keyboard" :digital="true" :disorderly="false" @typing="typing" @enter="enter" @cancel="cancel"> </VKeyboard> </view>
             <view class="keyboard-body_box"> <VKeyboard ref="keyboard" :digital="true" :disorderly="false" @typing="typing" @enter="enter" @cancel="cancel"> </VKeyboard> </view>
@@ -253,6 +259,8 @@ import { getAllStaff} from '@/api/shop-admin'
 import { merchantDetail } from '@/api/merchant' 
 import { merchantDetail } from '@/api/merchant' 
 import { quickOrderAllDeliveryQuotes } from '@/api/delivery'
 import { quickOrderAllDeliveryQuotes } from '@/api/delivery'
 import { getAvailableHb } from "@/api/hb"
 import { getAvailableHb } from "@/api/hb"
+import { getDetail } from '@/api/custom'
+import { currentShop as fetchCurrentShop } from '@/api/shop'
 import { mapGetters } from "vuex";
 import { mapGetters } from "vuex";
 export default {
 export default {
     name:'selectCustomer',
     name:'selectCustomer',
@@ -301,8 +309,13 @@ export default {
             shopAdminIdList:[],
             shopAdminIdList:[],
             diffData:[],
             diffData:[],
             discountList:[{name:'1折',value:0.1},{name:'2折',value:0.2},{name:'3折',value:0.3},{name:'4折',value:0.4},{name:'5折',value:0.5},{name:'6折',value:0.6},{name:'7折',value:0.7},{name:'8折',value:0.8},{name:'9折',value:0.9},{name:'不打折',value:1}],
             discountList:[{name:'1折',value:0.1},{name:'2折',value:0.2},{name:'3折',value:0.3},{name:'4折',value:0.4},{name:'5折',value:0.5},{name:'6折',value:0.6},{name:'7折',value:0.7},{name:'8折',value:0.8},{name:'9折',value:0.9},{name:'不打折',value:1}],
+            /** 0=未选手动打折(走会员/门店互斥);>0 已选手动折扣,1=不打折(也不套会员/门店) */
             discountValue:0,
             discountValue:0,
             showDiscount:false,
             showDiscount:false,
+            /** 结算时拉取的客户详情,用于会员折扣;避免选客列表缺 discount */
+            customInfo:{},
+            /** 结算时拉取的门店满减配置;避免仅依赖登录态缓存过期或缺字段 */
+            shopMeetCutConfig:{},
             deliveryQuotes: [], // 跑腿平台报价列表
             deliveryQuotes: [], // 跑腿平台报价列表
             selectedDeliveryIndex: -1,
             selectedDeliveryIndex: -1,
             selectedDeliveryData: null,
             selectedDeliveryData: null,
@@ -353,7 +366,41 @@ export default {
     components:{ VKeyboard, TimePicker, WeightInput, RemarkInput, HbSelect, DiscountPanel },
     components:{ VKeyboard, TimePicker, WeightInput, RemarkInput, HbSelect, DiscountPanel },
 	mixins: [productMins],
 	mixins: [productMins],
     computed:{
     computed:{
-        ...mapGetters(["getLoginInfo"]),
+        ...mapGetters(["getLoginInfo", "getMyShopInfo"]),
+        /**
+         * 是否已手动操作打折弹层:discountValue>0(含 1=不打折)。
+         * 不打折时应付金额=总金额原价,也不再套会员折扣/门店满减。
+         */
+        isManualDiscountActive() {
+            return Number(this.discountValue) > 0
+        },
+        /**
+         * 会员折扣与门店满减互斥结果,口径对齐 WholeOrderDiscountClass / hdApp affirm。
+         * bigNum 用花材扎数(pad mixin 的 allCount.bigNum)。
+         */
+        wholeDiscountPick() {
+            if (!this.$util.isEmpty(this.groupInfo)) {
+                return { type: 'none', amount: 0 }
+            }
+            const bigNum = Number(this.allCount && this.allCount.bigNum) || 0
+            return this.pickWholeOrderDiscount(this.systemPrice, bigNum)
+        },
+        /** 应付金额旁文案:会员折扣 / 门店满减优惠;手动选打折或不打折后不再展示 */
+        wholeDiscountLabel() {
+            if (this.isManualDiscountActive) return ''
+            const type = this.wholeDiscountPick.type
+            if (!(Number(this.wholeDiscountPick.amount) > 0)) return ''
+            if (type === 'member') return '会员折扣'
+            if (type === 'shop') return '门店满减优惠'
+            return ''
+        },
+        /** 应付金额旁优惠额,如 -¥10 */
+        wholeDiscountAmountText() {
+            if (this.isManualDiscountActive) return ''
+            const amount = Number(this.wholeDiscountPick.amount) || 0
+            if (amount <= 0) return ''
+            return `-¥${parseFloat(amount.toFixed(2))}`
+        },
         // 总金额, 也就是合计金额
         // 总金额, 也就是合计金额
         totalPrice(){
         totalPrice(){
             return this.systemPrice
             return this.systemPrice
@@ -444,13 +491,33 @@ export default {
         },
         },
     },
     },
     watch:{
     watch:{
-        // systemPrice 变化时,默认回填应付金额
+        // 总金额变化时,默认应付扣掉互斥整单优惠(会员折扣/门店满减取大);手选折扣则按倍率
         systemPrice: {
         systemPrice: {
             handler(val){
             handler(val){
-                this.form.modifyPrice = val
+                this.syncModifyPriceWithWholeDiscount(val)
             },
             },
             immediate: true
             immediate: true
         },
         },
+        // 客户折扣或门店满减配置变化时同步默认应付金额
+        'customInfo.discount'() {
+            this.syncModifyPriceWithWholeDiscount(this.systemPrice)
+        },
+        getMyShopInfo: {
+            handler() {
+                this.syncModifyPriceWithWholeDiscount(this.systemPrice)
+            },
+            deep: true
+        },
+        shopMeetCutConfig: {
+            handler() {
+                this.syncModifyPriceWithWholeDiscount(this.systemPrice)
+            },
+            deep: true
+        },
+        // 扎数变化可能只影响满减门槛,金额不变时也要重算互斥优惠
+        'allCount.bigNum'() {
+            this.syncModifyPriceWithWholeDiscount(this.systemPrice)
+        },
         settleOpenStatus:{
         settleOpenStatus:{
             handler(val){
             handler(val){
                 if(Number(val) == 1){
                 if(Number(val) == 1){
@@ -464,12 +531,19 @@ export default {
                     this.form.dealPrice = 0
                     this.form.dealPrice = 0
                     this.form.sendType = 1
                     this.form.sendType = 1
                     this.form.getGoods = 1
                     this.form.getGoods = 1
+                    // 每次打开弹窗重新走自动优惠,避免上次手选折扣残留
+                    this.discountValue = 0
+                    this.showDiscount = false
+                    this.customInfo = this.custom || {}
+                    // 先用登录态门店兜底,再拉最新满减配置
+                    this.shopMeetCutConfig = (this.getMyShopInfo && this.getMyShopInfo.shop) || {}
                     // 重置红包选择,避免上次结算残留
                     // 重置红包选择,避免上次结算残留
                     this.selectedHbId = null
                     this.selectedHbId = null
                     this.selectedHb = null
                     this.selectedHb = null
                     this.form.hbId = null
                     this.form.hbId = null
                     this.form.hbAmount = null
                     this.form.hbAmount = null
 
 
+                    this.syncModifyPriceWithWholeDiscount(this.systemPrice)
                     //如果余额够使用余额支付
                     //如果余额够使用余额支付
                     if(Number(this.balance)>Number(this.form.modifyPrice)){
                     if(Number(this.balance)>Number(this.form.modifyPrice)){
                         this.changeHasPay(4)
                         this.changeHasPay(4)
@@ -490,6 +564,16 @@ export default {
                         }
                         }
                     })
                     })
 
 
+                    // 拉客户折扣 + 门店满减后再回填应付;余额是否够付也按折后金额判断
+                    Promise.all([
+                        this.loadSettleCustom(),
+                        this.loadCurrentShopForDiscount()
+                    ]).then(() => {
+                        if(Number(this.balance)>Number(this.form.modifyPrice)){
+                            this.changeHasPay(4)
+                        }
+                    })
+
                     //获取可用红包数据
                     //获取可用红包数据
                     this.getHbData()
                     this.getHbData()
                 }
                 }
@@ -574,6 +658,127 @@ export default {
         }
         }
     },
     },
     methods: {
     methods: {
+        /**
+         * 结算弹窗拉取客户详情,拿到 custom.discount 才能算会员折扣。
+         * 选客列表不一定带折扣字段,所以打开弹窗时再请求 /custom/detail。
+         */
+        loadSettleCustom() {
+            const id = Number(this.customId)
+            if (!(id > 0)) {
+                this.customInfo = this.custom || {}
+                this.syncModifyPriceWithWholeDiscount(this.systemPrice)
+                return Promise.resolve()
+            }
+            return getDetail({ userId: id }).then(res => {
+                if (res.code == 1 && res.data) {
+                    this.customInfo = res.data
+                } else {
+                    this.customInfo = this.custom || {}
+                }
+                this.syncModifyPriceWithWholeDiscount(this.systemPrice)
+            }).catch(() => {
+                this.customInfo = this.custom || {}
+                this.syncModifyPriceWithWholeDiscount(this.systemPrice)
+            })
+        },
+        /**
+         * 拉取当前门店满减配置(meetNum/meetAmount/cutAmount/cutStyle)。
+         * 原因:登录态 getMyShopInfo.shop 可能过期或未就绪;与 hdApp affirm 对齐,结算时再拉一次。
+         */
+        loadCurrentShopForDiscount() {
+            return fetchCurrentShop().then(res => {
+                if (res.code == 1 && res.data) {
+                    this.shopMeetCutConfig = res.data
+                    this.syncModifyPriceWithWholeDiscount(this.systemPrice)
+                }
+            }).catch(() => {})
+        },
+        /**
+         * 回写默认应付金额:
+         * - 组合单:应付=总金额,不套会员/门店
+         * - 已手动选打折/不打折:systemPrice * discountValue(不打折时为 1,即原价)
+         * - 未手动选:systemPrice - 互斥整单优惠额
+         */
+        syncModifyPriceWithWholeDiscount(systemPrice) {
+            const base = Number(systemPrice) || 0
+            if (!this.$util.isEmpty(this.groupInfo)) {
+                this.form.modifyPrice = parseFloat(base.toFixed(2))
+                return
+            }
+            if (this.isManualDiscountActive) {
+                const rate = Number(this.discountValue) || 1
+                this.form.modifyPrice = parseFloat((base * rate).toFixed(2))
+                return
+            }
+            const bigNum = Number(this.allCount && this.allCount.bigNum) || 0
+            const pick = this.pickWholeOrderDiscount(base, bigNum)
+            let price = base - (Number(pick.amount) || 0)
+            if (price < 0) price = 0
+            this.form.modifyPrice = parseFloat(price.toFixed(2))
+        },
+        /**
+         * 会员折扣与门店满减互斥取大,对齐后端 WholeOrderDiscountClass。
+         * @param {number} basePrice 总金额(已减红包)
+         * @param {number} bigNum 花材扎数
+         */
+        pickWholeOrderDiscount(basePrice, bigNum) {
+            const memberSave = this.calcMemberDiscountSave(basePrice)
+            const shopSave = this.calcShopMeetCutSave(basePrice, bigNum)
+            // 相等时用会员折扣,只扣一笔
+            if (memberSave >= shopSave && memberSave > 0) {
+                return { type: 'member', amount: memberSave }
+            }
+            if (shopSave > 0) {
+                return { type: 'shop', amount: shopSave }
+            }
+            return { type: 'none', amount: 0 }
+        },
+        /**
+         * 会员折扣额:custom.discount ∈ (0,1) 时 base*(1-discount);折后≤0 按后端保底 0.01。
+         */
+        calcMemberDiscountSave(basePrice) {
+            const base = Number(Number(basePrice || 0).toFixed(2))
+            const discount = Number(this.customInfo && this.customInfo.discount)
+            if (!(discount > 0 && discount < 1) || base <= 0) {
+                return 0
+            }
+            let after = Number((base * discount).toFixed(2))
+            if (after <= 0) {
+                after = 0.01
+            }
+            const save = Number((base - after).toFixed(2))
+            return save > 0 ? save : 0
+        },
+        /**
+         * 门店满减额:件数+金额双门槛,cutStyle=0 固定额、=1 按折扣乘算;满减不得 ≥ 应付。
+         */
+        calcShopMeetCutSave(basePrice, bigNum) {
+            const base = Number(Number(basePrice || 0).toFixed(2))
+            // 优先用结算时拉取的门店配置,其次登录态 shop,避免满减字段缺失
+            const shop = (this.shopMeetCutConfig && Object.keys(this.shopMeetCutConfig).length)
+                ? this.shopMeetCutConfig
+                : ((this.getMyShopInfo && this.getMyShopInfo.shop) || {})
+            const meetNum = Number(shop.meetNum) || 0
+            const meetAmount = Number(shop.meetAmount) || 0
+            const cutOption = Number(shop.cutAmount) || 0
+            const cutStyle = Number(shop.cutStyle) || 0
+            let cutAmount = 0
+            if (cutStyle === 0) {
+                cutAmount = Number(cutOption.toFixed(2))
+            } else {
+                cutAmount = Number((base * (1 - cutOption)).toFixed(2))
+            }
+            if (!(cutAmount > 0 && meetNum >= 0 && meetAmount > 0)) {
+                return 0
+            }
+            if (Number(bigNum || 0) < meetNum || base < meetAmount) {
+                return 0
+            }
+            if (cutAmount >= base) {
+                return 0
+            }
+            return cutAmount
+        },
         confirmDiff(){
         confirmDiff(){
             this.$util.hitVoice()
             this.$util.hitVoice()
             this.form.dealPrice = 1
             this.form.dealPrice = 1
@@ -596,8 +801,12 @@ export default {
         },
         },
         setDiscount(num){
         setDiscount(num){
             this.$util.hitVoice()
             this.$util.hitVoice()
+            // 含「不打折」(value=1):应付按手选倍率,不再套会员折扣/门店满减
             this.discountValue = Number(num)
             this.discountValue = Number(num)
-            let price = Number(this.systemPrice)*Number(num)
+            if (!(this.discountValue > 0)) {
+                this.discountValue = 1
+            }
+            let price = Number(this.systemPrice) * Number(this.discountValue)
             price = parseFloat(price.toFixed(2))
             price = parseFloat(price.toFixed(2))
             this.form.modifyPrice = price
             this.form.modifyPrice = price
             this.showDiscount = false
             this.showDiscount = false
@@ -935,6 +1144,10 @@ export default {
                 }
                 }
             }
             }
 
 
+            // 应付已含会员折扣/门店满减或手选折扣,禁止服务端再折/再满减
+            this.form.skipMemberDiscount = 1
+            this.form.skipShopMeetCut = 1
+
             this.$emit('settleCommit',this.form)
             this.$emit('settleCommit',this.form)
         },
         },
         cancel(){
         cancel(){
@@ -1087,6 +1300,44 @@ export default {
                 background: #F0FFF7;
                 background: #F0FFF7;
                 box-sizing: border-box;
                 box-sizing: border-box;
             }
             }
+            /* 应付金额行:左标题、中优惠、右金额 */
+            &.payable-row {
+                .payable-label {
+                    flex-shrink: 0;
+                    min-width: 70upx;
+                }
+                .payable-price {
+                    flex-shrink: 0;
+                    min-width: 70upx;
+                    text-align: right;
+                }
+                .payable-discount {
+                    flex: 1;
+                    display: flex;
+                    justify-content: center;
+                    align-items: center;
+                    min-width: 0;
+                }
+            }
+            /* 应付金额旁会员折扣/满减:红底白字居中,避免被小字号忽略 */
+            .price-hint-tag {
+                padding: 2upx 8upx;
+                border-radius: 4upx;
+                background-color: #ff2842;
+                .price-hint-text {
+                    color: #fff;
+                    font-size: 11upx;
+                    font-weight: bold;
+                    line-height: 1.2;
+                    text-align: center;
+                }
+            }
+            .generic-save-text {
+                color: #ff2842;
+                font-size: 11upx;
+                font-weight: bold;
+                text-align: center;
+            }
         }
         }
         & .input-bottom{
         & .input-bottom{
             margin-bottom:10upx;
             margin-bottom:10upx;