|
|
@@ -1,6 +1,8 @@
|
|
|
<!--
|
|
|
混合结算页(花束+花材),立即购买
|
|
|
用途:商城混合购物车确认下单,支持多种配送方式、红包、贺卡与匿名配送
|
|
|
+ 整单优惠:会员折扣与门店满减互斥,左侧名称、右侧 -¥N,只展示优惠金额更大的一项
|
|
|
+ 布局:贺卡/匿名/备注后为运费+折扣+红包同一卡片;贺卡默认不需要,匿名默认否,备注单行
|
|
|
顶部公告:/shop-notice/show-list position=8(订单提交),公告条与分类页 shop-category 同款(noticeBar)
|
|
|
-->
|
|
|
<template>
|
|
|
@@ -296,12 +298,6 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
</view>
|
|
|
- <view class="affirm-card fee-card" v-if="Number(form.unMeetSendCost) > 0">
|
|
|
- <view class="fee-row">
|
|
|
- <text class="fee-label">运费</text>
|
|
|
- <text class="accent-text">¥{{ form.unMeetSendCost }}</text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
<view class="affirm-card fee-card" v-if="(form.sendType == 2 || form.sendType == 0 || form.sendType == 3 || form.sendType == 4) && Number(form.packCost) > 0">
|
|
|
<view class="fee-row">
|
|
|
<text class="fee-label">包装费</text>
|
|
|
@@ -309,7 +305,7 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 贺卡:标题 + 切换按钮 + 多行输入,样式对齐设计稿 -->
|
|
|
+ <!-- 贺卡:默认不需要 -->
|
|
|
<view class="affirm-card card-section">
|
|
|
<text class="plain-section-title">贺卡</text>
|
|
|
<view class="card-toggle">
|
|
|
@@ -338,49 +334,65 @@
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 红包/红包行:样式对齐设计稿,整行可点(弹层组件放页面级,避免点击被父级拦截) -->
|
|
|
- <view class="affirm-card hb-row-card" @click="openHbPopup">
|
|
|
- <view class="hb-row-left">
|
|
|
- <sprite-icon name="youhuiquan" sheet="order" :height="35" custom-class="hb-row-icon" />
|
|
|
- <text class="hb-row-title">红包</text>
|
|
|
- <text class="hb-row-desc">选择红包</text>
|
|
|
- </view>
|
|
|
- <view class="hb-row-right">
|
|
|
- <text
|
|
|
- class="hb-row-value"
|
|
|
- :class="{
|
|
|
- 'hb-row-value--highlight': selectedHbId,
|
|
|
- 'hb-row-value--available': hasAvailableHb && !selectedHbId
|
|
|
- }"
|
|
|
- >{{ hbRowText }}</text>
|
|
|
- <text class="iconfont iconxiangyou hb-row-arrow"></text>
|
|
|
- </view>
|
|
|
- </view>
|
|
|
-
|
|
|
- <!-- 匿名配送:文案左、当前是/否 + 开关右,默认开启 -->
|
|
|
+ <!-- 匿名配送:默认否 -->
|
|
|
<view class="affirm-card anonymity-row">
|
|
|
<text class="anonymity-label">是否匿名</text>
|
|
|
<view class="anonymity-control">
|
|
|
- <!-- 开关旁展示当前选择,避免只靠颜色判断是或否 -->
|
|
|
<text class="anonymity-value">{{ form.anonymity == 1 ? '是' : '否' }}</text>
|
|
|
<switch :checked="form.anonymity == 1" @change="onAnonymityChange" color="#77c34f" />
|
|
|
</view>
|
|
|
</view>
|
|
|
|
|
|
- <!-- 备注 -->
|
|
|
+ <!-- 备注:单行输入 -->
|
|
|
<view class="affirm-card remark-section">
|
|
|
<text class="plain-section-title">备注</text>
|
|
|
- <view class="remark-wrap textarea-box">
|
|
|
- <textarea
|
|
|
- class="remark-input"
|
|
|
+ <view class="remark-wrap remark-line-box">
|
|
|
+ <input
|
|
|
+ class="remark-line-input"
|
|
|
+ type="text"
|
|
|
v-model="form.remark"
|
|
|
- maxlength="200"
|
|
|
+ maxlength="50"
|
|
|
placeholder="请输入备注信息"
|
|
|
placeholder-class="input-placeholder"
|
|
|
- :auto-height="false"
|
|
|
- :show-confirm-bar="false"
|
|
|
+ confirm-type="done"
|
|
|
/>
|
|
|
- <text class="char-count char-count--inner">{{ remarkLength }}/200</text>
|
|
|
+ </view>
|
|
|
+ </view>
|
|
|
+
|
|
|
+ <!-- 运费、会员折扣、红包同一卡片;红包行单独可点,避免点运费也弹层 -->
|
|
|
+ <view class="affirm-card fee-card fee-hb-card">
|
|
|
+ <view class="fee-row" v-if="Number(form.unMeetSendCost) > 0">
|
|
|
+ <text class="fee-label">运费</text>
|
|
|
+ <text class="accent-text">¥{{ form.unMeetSendCost }}</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="fee-row"
|
|
|
+ :class="{ 'fee-row--follow': Number(form.unMeetSendCost) > 0 }"
|
|
|
+ v-if="wholeDiscountLabel"
|
|
|
+ >
|
|
|
+ <text class="fee-label">{{ wholeDiscountLabel }}</text>
|
|
|
+ <text :class="wholeDiscountAmountClass">{{ wholeDiscountAmountText }}</text>
|
|
|
+ </view>
|
|
|
+ <view
|
|
|
+ class="hb-row-inner"
|
|
|
+ :class="{ 'fee-row--follow': Number(form.unMeetSendCost) > 0 || !!wholeDiscountLabel }"
|
|
|
+ @click="openHbPopup"
|
|
|
+ >
|
|
|
+ <view class="hb-row-left">
|
|
|
+ <sprite-icon name="youhuiquan" sheet="order" :height="35" custom-class="hb-row-icon" />
|
|
|
+ <text class="hb-row-title">红包</text>
|
|
|
+ <text class="hb-row-desc">选择红包</text>
|
|
|
+ </view>
|
|
|
+ <view class="hb-row-right">
|
|
|
+ <text
|
|
|
+ class="hb-row-value"
|
|
|
+ :class="{
|
|
|
+ 'hb-row-value--highlight': selectedHbId,
|
|
|
+ 'hb-row-value--available': hasAvailableHb && !selectedHbId
|
|
|
+ }"
|
|
|
+ >{{ hbRowText }}</text>
|
|
|
+ <text class="iconfont iconxiangyou hb-row-arrow"></text>
|
|
|
+ </view>
|
|
|
</view>
|
|
|
</view>
|
|
|
</form>
|
|
|
@@ -548,12 +560,14 @@ export default {
|
|
|
openIntraCity: 0,
|
|
|
receiveUserName: "",
|
|
|
receiveMobile: "",
|
|
|
- needCard: 1,
|
|
|
+ needCard: 0,
|
|
|
cardInfo: "",
|
|
|
- anonymity: 1
|
|
|
+ anonymity: 0
|
|
|
},
|
|
|
userInfo: {},
|
|
|
shopInfo: {},
|
|
|
+ /** 花店客户折扣 0~1,1 表示无折扣;与后端 custom.discount 对齐 */
|
|
|
+ customDiscount: 1,
|
|
|
account: 0,
|
|
|
showDistance: 0,
|
|
|
deliveryQuotes: [],
|
|
|
@@ -712,7 +726,11 @@ export default {
|
|
|
return isHbAvailable(item, this.hbProductList, this.allPriceFun);
|
|
|
});
|
|
|
},
|
|
|
- modifyPrice() {
|
|
|
+ /**
|
|
|
+ * 整单互斥优惠前的应付:商品合计 + 运费/包装 - 红包。
|
|
|
+ * 与后端 actionCreateMixOrder 红包后的 modifyPrice 对齐,作为会员折扣/门店满减比较基数。
|
|
|
+ */
|
|
|
+ wholeDiscountBasePrice() {
|
|
|
let price = Number(this.mixGoodsPrice) || 0;
|
|
|
|
|
|
if (this.hasAvailableHb && this.selectedHbId) {
|
|
|
@@ -728,8 +746,37 @@ export default {
|
|
|
} else if ([0, 3, 4].includes(Number(this.form.sendType))) {
|
|
|
price = price + unMeetSend + packCost;
|
|
|
}
|
|
|
- price = price.toFixed(2);
|
|
|
- return parseFloat(price);
|
|
|
+ return parseFloat(price.toFixed(2));
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 会员折扣与门店满减互斥结果:type=member|shop|none,amount 为优惠额。
|
|
|
+ */
|
|
|
+ wholeDiscountPick() {
|
|
|
+ return this.pickWholeOrderDiscount(this.wholeDiscountBasePrice, this.mixOrderBigNum);
|
|
|
+ },
|
|
|
+ /** 确认页费用行左侧:会员折扣 / 门店满减优惠 */
|
|
|
+ wholeDiscountLabel() {
|
|
|
+ const type = this.wholeDiscountPick.type;
|
|
|
+ if (!(Number(this.wholeDiscountPick.amount) > 0)) return "";
|
|
|
+ if (type === "member") return "会员折扣";
|
|
|
+ if (type === "shop") return "门店优惠";
|
|
|
+ return "";
|
|
|
+ },
|
|
|
+ /** 确认页费用行右侧优惠金额,如 -¥10 */
|
|
|
+ wholeDiscountAmountText() {
|
|
|
+ const amount = Number(this.wholeDiscountPick.amount) || 0;
|
|
|
+ if (amount <= 0) return "";
|
|
|
+ return `-¥${parseFloat(amount.toFixed(2))}`;
|
|
|
+ },
|
|
|
+ /** 会员折扣、门店满减右侧金额统一用 #ff2842 */
|
|
|
+ wholeDiscountAmountClass() {
|
|
|
+ return "fee-discount-amount";
|
|
|
+ },
|
|
|
+ modifyPrice() {
|
|
|
+ let price = Number(this.wholeDiscountBasePrice) || 0;
|
|
|
+ price = price - (Number(this.wholeDiscountPick.amount) || 0);
|
|
|
+ if (price < 0) price = 0;
|
|
|
+ return parseFloat(price.toFixed(2));
|
|
|
},
|
|
|
/** 混合单花材扎数(与提交 product.num 一致:仅支数时按 smallCount/ratio 折算) */
|
|
|
mixItemBigNum() {
|
|
|
@@ -904,9 +951,6 @@ export default {
|
|
|
cardInfoLength() {
|
|
|
return (this.form.cardInfo || "").length;
|
|
|
},
|
|
|
- remarkLength() {
|
|
|
- return (this.form.remark || "").length;
|
|
|
- },
|
|
|
/** 是否已选择有效收货地址 */
|
|
|
hasSelectedAddress() {
|
|
|
return this.validAddress && !this.$util.isEmpty(this.userInfo.lat) && !this.$util.isEmpty(this.userInfo.long);
|
|
|
@@ -1008,6 +1052,67 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
methods: {
|
|
|
+ /**
|
|
|
+ * 会员折扣与门店满减互斥取大,口径对齐后端 WholeOrderDiscountClass。
|
|
|
+ * @param {number} basePrice 商品+运费包装-红包
|
|
|
+ * @param {number} bigNum 花材扎数+花束份数
|
|
|
+ * @returns {{ type: string, amount: number }}
|
|
|
+ */
|
|
|
+ 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.customDiscount);
|
|
|
+ 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));
|
|
|
+ const shop = this.shopInfo || {};
|
|
|
+ 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;
|
|
|
+ },
|
|
|
/**
|
|
|
* 将购物车 selectList 按行唯一键合并,得到结算明细(购物车结算用)。
|
|
|
* 立即购买模式不走这里,直接使用详情页传入的单商品明细。
|
|
|
@@ -1210,6 +1315,8 @@ export default {
|
|
|
this.mergePickupShopInfo(res.data.info, res.data.hd);
|
|
|
uni.setStorageSync("currentShop", res.data.info);
|
|
|
}
|
|
|
+ // 客户折扣用于整单互斥优惠;无客户时按 1(不打折)
|
|
|
+ this.applyCustomDiscount(res.data.custom, res.data.hd);
|
|
|
this.getHbData();
|
|
|
}
|
|
|
}).catch(() => {});
|
|
|
@@ -1227,6 +1334,23 @@ export default {
|
|
|
}
|
|
|
}).catch(() => {});
|
|
|
},
|
|
|
+ /**
|
|
|
+ * 写入花店客户折扣,供会员折扣与门店满减互斥比较。
|
|
|
+ * 优先 custom.discount,其次 hd.discount;无效则视为 1(不打折)。
|
|
|
+ */
|
|
|
+ applyCustomDiscount(custom, hd) {
|
|
|
+ const fromCustom = custom && custom.discount != null ? Number(custom.discount) : NaN;
|
|
|
+ const fromHd = hd && hd.discount != null ? Number(hd.discount) : NaN;
|
|
|
+ if (fromCustom > 0) {
|
|
|
+ this.customDiscount = fromCustom;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (fromHd > 0) {
|
|
|
+ this.customDiscount = fromHd;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.customDiscount = 1;
|
|
|
+ },
|
|
|
/** 合并门店详情,供到店自取信息展示 */
|
|
|
mergePickupShopInfo(info, hd) {
|
|
|
if (!info) return;
|
|
|
@@ -2825,6 +2949,10 @@ export default {
|
|
|
justify-content: space-between;
|
|
|
}
|
|
|
|
|
|
+.fee-row--follow {
|
|
|
+ margin-top: 20upx;
|
|
|
+}
|
|
|
+
|
|
|
.fee-label {
|
|
|
font-size: 28upx;
|
|
|
color: #333333;
|
|
|
@@ -2848,6 +2976,17 @@ export default {
|
|
|
font-weight: bold;
|
|
|
}
|
|
|
|
|
|
+.fee-discount-amount {
|
|
|
+ color: #ff2842;
|
|
|
+ font-size: 28upx;
|
|
|
+ font-weight: bold;
|
|
|
+}
|
|
|
+
|
|
|
+/* 运费+折扣+红包卡片下方留 20px,避免贴底栏 */
|
|
|
+.fee-hb-card {
|
|
|
+ margin-bottom: 60upx;
|
|
|
+}
|
|
|
+
|
|
|
/* 时间选择 */
|
|
|
.time-select-group {
|
|
|
display: flex;
|
|
|
@@ -3083,6 +3222,28 @@ export default {
|
|
|
margin-top: 24upx;
|
|
|
}
|
|
|
|
|
|
+/* 备注单行:高度约一行文字,不占用贺卡多行输入框 */
|
|
|
+.remark-line-box {
|
|
|
+ background-color: #fafafa;
|
|
|
+ border: 2upx solid #e8e8e8;
|
|
|
+ border-radius: 12upx;
|
|
|
+ box-sizing: border-box;
|
|
|
+ overflow: hidden;
|
|
|
+}
|
|
|
+
|
|
|
+.remark-line-input {
|
|
|
+ display: block;
|
|
|
+ width: 100%;
|
|
|
+ height: 72upx;
|
|
|
+ padding: 0 24upx;
|
|
|
+ font-size: 28upx;
|
|
|
+ line-height: 72upx;
|
|
|
+ color: #333333;
|
|
|
+ background-color: transparent;
|
|
|
+ border: none;
|
|
|
+ box-sizing: border-box;
|
|
|
+}
|
|
|
+
|
|
|
/* 贺卡/备注输入区:外框统一边框,固定约两行输入高度 */
|
|
|
.textarea-box {
|
|
|
position: relative;
|
|
|
@@ -3095,8 +3256,7 @@ export default {
|
|
|
overflow: hidden;
|
|
|
}
|
|
|
|
|
|
-.card-info-input,
|
|
|
-.remark-input {
|
|
|
+.card-info-input {
|
|
|
display: block;
|
|
|
width: 100%;
|
|
|
height: 80upx;
|
|
|
@@ -3141,16 +3301,13 @@ export default {
|
|
|
z-index: 1000;
|
|
|
}
|
|
|
|
|
|
-/* 红包行:设计稿单行布局,整行可点 */
|
|
|
-.hb-row-card {
|
|
|
+/* 红包行:与运费同卡时作为卡片内一行,不再单独成卡 */
|
|
|
+.hb-row-inner {
|
|
|
display: flex;
|
|
|
flex-direction: row;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
- position: relative;
|
|
|
- min-height: 96upx;
|
|
|
- padding-top: 28upx;
|
|
|
- padding-bottom: 28upx;
|
|
|
+ min-height: 56upx;
|
|
|
box-sizing: border-box;
|
|
|
}
|
|
|
|