|
|
@@ -386,7 +386,7 @@
|
|
|
class="affirm-hb-select-host"
|
|
|
hide-trigger
|
|
|
:hbData="hbData"
|
|
|
- :totalPrice="allPriceFun"
|
|
|
+ :totalPrice="mixGoodsPrice"
|
|
|
v-model="selectedHbId"
|
|
|
@change="onHbChange"
|
|
|
></hb-select>
|
|
|
@@ -496,7 +496,7 @@ import { currentInfo } from "@/api/user";
|
|
|
import { getInfo } from "@/api/shop";
|
|
|
import { getAddressList } from "@/api/user-address";
|
|
|
import { getAvailableHb } from "@/api/hb";
|
|
|
-import { getAllPsMethod } from "@/api/ps-method";
|
|
|
+import { getAllPsMethod, calcMixFeeBatch } from "@/api/ps-method";
|
|
|
import MxDatePicker from "@/components/mx-datepicker/mx-datepicker.vue";
|
|
|
import HbSelect from "@/components/hb/hb-select";
|
|
|
|
|
|
@@ -577,7 +577,15 @@ export default {
|
|
|
psMethodList: [],
|
|
|
/** 是否已拉取过默认地址,避免切换购买方式重复请求 */
|
|
|
defaultAddressLoaded: false,
|
|
|
- defaultAddressLoading: false
|
|
|
+ defaultAddressLoading: false,
|
|
|
+ /** 各购买方式附加费预览缓存(进页/金额变化时批量拉取,切换方式只读缓存) */
|
|
|
+ unMeetFeeBySendType: {},
|
|
|
+ unMeetFeePreview: {
|
|
|
+ tip: "",
|
|
|
+ canOrder: true,
|
|
|
+ belowMinimum: false
|
|
|
+ },
|
|
|
+ unMeetFeeBatchTimer: null
|
|
|
};
|
|
|
},
|
|
|
onLoad() {
|
|
|
@@ -605,24 +613,26 @@ export default {
|
|
|
|
|
|
this.loadShopInfo();
|
|
|
this.loadSelectedAddress();
|
|
|
+ // 附加费在 loadPsMethods 中与配送方式一并批量返回
|
|
|
// 商品金额变化后刷新红包可用性(对齐 affirmGhs onShow)
|
|
|
if (this.shopInfo && this.shopInfo.id) {
|
|
|
this.getHbData();
|
|
|
}
|
|
|
},
|
|
|
watch: {
|
|
|
- /** 商品总价变化时,剔除已不满足门槛的红包,并同步未达门槛附加费 */
|
|
|
- allPriceFun() {
|
|
|
+ /** 商品总价变化时,剔除红包并批量刷新附加费缓存(不随购买方式切换重复请求) */
|
|
|
+ mixGoodsPrice() {
|
|
|
this.syncSelectedHbAfterPriceChange();
|
|
|
- this.syncUnMeetFee();
|
|
|
+ this.loadUnMeetFeeBatch();
|
|
|
this.recheckRunnerFreeDelivery();
|
|
|
},
|
|
|
- /** 购买方式切换后同步附加费;跑腿时重算是否免配送费 */
|
|
|
+ /** 切换购买方式:读缓存;style=2 跑腿仍按地址重算距离运费 */
|
|
|
"form.sendType"() {
|
|
|
- this.syncUnMeetFee();
|
|
|
+ this.applyCurrentUnMeetFee();
|
|
|
this.recheckRunnerFreeDelivery();
|
|
|
},
|
|
|
mixItemBigNum() {
|
|
|
+ this.loadUnMeetFeeBatch();
|
|
|
this.recheckRunnerFreeDelivery();
|
|
|
}
|
|
|
},
|
|
|
@@ -675,14 +685,14 @@ export default {
|
|
|
if (!this.hbData || this.hbData.length === 0) {
|
|
|
return false;
|
|
|
}
|
|
|
- const price = this.allPriceFun;
|
|
|
+ const price = this.mixGoodsPrice;
|
|
|
return this.hbData.some((item) => {
|
|
|
const min = Number(item.minConsume) || 0;
|
|
|
return price >= min;
|
|
|
});
|
|
|
},
|
|
|
modifyPrice() {
|
|
|
- let price = Number(this.allPriceFun) || 0;
|
|
|
+ let price = Number(this.mixGoodsPrice) || 0;
|
|
|
|
|
|
if (this.hasAvailableHb && this.selectedHbId) {
|
|
|
price = price - Number(this.selectedHb.amount);
|
|
|
@@ -700,36 +710,25 @@ export default {
|
|
|
price = price.toFixed(2);
|
|
|
return parseFloat(price);
|
|
|
},
|
|
|
- /** 混合单花材扎数(花束不计入最低消费数量) */
|
|
|
+ /** 混合单花材扎数(与提交 product.num 一致:仅支数时按 smallCount/ratio 折算) */
|
|
|
mixItemBigNum() {
|
|
|
let bigLength = 0;
|
|
|
(this.list || []).forEach((item) => {
|
|
|
- if (!this.isBouquetItem(item)) {
|
|
|
+ if (this.isBouquetItem(item)) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (Number(item.smallCount) > 0) {
|
|
|
+ const ratio = Number(item.ratio) || 1;
|
|
|
+ bigLength += Number(item.smallCount) / ratio;
|
|
|
+ } else {
|
|
|
bigLength += Number(item.bigCount) || 0;
|
|
|
}
|
|
|
});
|
|
|
return bigLength;
|
|
|
},
|
|
|
- /** 未达最低消费时在配送说明中展示的提示(单行) */
|
|
|
+ /** 未达最低消费提示(来自批量预览缓存,与下单 calcFee 同源) */
|
|
|
unMeetWarningText() {
|
|
|
- const method = this.currentPsMethod;
|
|
|
- if (!method || !this.checkPsMethodBelowMinimum(method)) {
|
|
|
- return "";
|
|
|
- }
|
|
|
- const unMeet = Number(method.unMeet) || 0;
|
|
|
- const fee = Number(method.unMeetFee) || 0;
|
|
|
- const conditionText = this.buildUnMeetConditionText(method);
|
|
|
- if (!conditionText) {
|
|
|
- return "";
|
|
|
- }
|
|
|
- if (unMeet === 1) {
|
|
|
- return `订单不满${conditionText},不能下单`;
|
|
|
- }
|
|
|
- if ((unMeet === 0 || unMeet === 2) && fee > 0) {
|
|
|
- const feeLabel = unMeet === 2 ? "包装费" : "运费";
|
|
|
- return `订单不满${conditionText},加${feeLabel}${fee}元`;
|
|
|
- }
|
|
|
- return "";
|
|
|
+ return (this.unMeetFeePreview && this.unMeetFeePreview.tip) || "";
|
|
|
},
|
|
|
displaySendCost() {
|
|
|
if (this.form.sendType == 2) {
|
|
|
@@ -740,23 +739,6 @@ export default {
|
|
|
}
|
|
|
return false;
|
|
|
},
|
|
|
- totalPrice() {
|
|
|
- let allPrice = Number(this.mixGoodsPrice).toFixed(2);
|
|
|
- allPrice = Number(allPrice);
|
|
|
- let price = allPrice;
|
|
|
-
|
|
|
- if (this.displaySendCost == true) {
|
|
|
- if (!this.isFreeDelivery) {
|
|
|
- price = price + this.form.sendCost;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- this.needAddPackCost = false;
|
|
|
- if (this.form.sendType == 4) {
|
|
|
- // 快递暂不额外加价
|
|
|
- }
|
|
|
- return price.toFixed(2);
|
|
|
- },
|
|
|
showDeliveryPolicy() {
|
|
|
if (!this.shopInfo) return false;
|
|
|
|
|
|
@@ -1005,16 +987,76 @@ export default {
|
|
|
if (!matched) {
|
|
|
this.changeSendType(options[0].value);
|
|
|
} else {
|
|
|
- this.syncUnMeetFee();
|
|
|
+ this.applyCurrentUnMeetFee();
|
|
|
this.ensureDefaultAddressIfNeeded();
|
|
|
}
|
|
|
},
|
|
|
- /** 拉取门店配送方式及说明(xhPsMethod / xhPsExplain) */
|
|
|
+ /** 批量预览接口入参(商品金额 + 花材扎数) */
|
|
|
+ getUnMeetFeeBatchParams() {
|
|
|
+ return {
|
|
|
+ itemTotalAmount: Number(this.mixGoodsPrice) || 0,
|
|
|
+ bigNum: Number(this.mixItemBigNum) || 0
|
|
|
+ };
|
|
|
+ },
|
|
|
+ /** 写入各 style 附加费缓存并应用到当前购买方式 */
|
|
|
+ setUnMeetFeeBatch(fees) {
|
|
|
+ if (!fees || typeof fees !== "object") {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ this.unMeetFeeBySendType = fees;
|
|
|
+ this.applyCurrentUnMeetFee();
|
|
|
+ },
|
|
|
+ /** 从缓存读取当前购买方式的附加费/提示(切换方式不调接口) */
|
|
|
+ applyCurrentUnMeetFee() {
|
|
|
+ const sendType = Number(this.form.sendType);
|
|
|
+ if (sendType < 0 || sendType > 4) {
|
|
|
+ this.form.unMeetSendCost = 0;
|
|
|
+ this.form.packCost = 0;
|
|
|
+ this.unMeetFeePreview = { tip: "", canOrder: true, belowMinimum: false };
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ const data = this.unMeetFeeBySendType[String(sendType)] || {};
|
|
|
+ this.form.unMeetSendCost = Number(data.unMeetSendCost != null ? data.unMeetSendCost : data.sendCost) || 0;
|
|
|
+ this.form.packCost = Number(data.packingFee != null ? data.packingFee : data.packCost) || 0;
|
|
|
+ this.unMeetFeePreview = {
|
|
|
+ tip: data.tip || "",
|
|
|
+ canOrder: data.canOrder !== false,
|
|
|
+ belowMinimum: !!data.belowMinimum
|
|
|
+ };
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 商品金额/扎数变化时防抖批量刷新附加费(style=2 跑腿距离运费仍走 getDeliveryQuotes)
|
|
|
+ */
|
|
|
+ loadUnMeetFeeBatch() {
|
|
|
+ if (this.unMeetFeeBatchTimer) {
|
|
|
+ clearTimeout(this.unMeetFeeBatchTimer);
|
|
|
+ }
|
|
|
+ this.unMeetFeeBatchTimer = setTimeout(() => {
|
|
|
+ this.unMeetFeeBatchTimer = null;
|
|
|
+ this.doLoadUnMeetFeeBatch();
|
|
|
+ }, 200);
|
|
|
+ },
|
|
|
+ /** 调用 calc-mix-fee-batch 刷新全量 style 缓存 */
|
|
|
+ doLoadUnMeetFeeBatch() {
|
|
|
+ const params = this.getUnMeetFeeBatchParams();
|
|
|
+ calcMixFeeBatch(params).then((res) => {
|
|
|
+ if (res.code == 1 && res.data && res.data.fees) {
|
|
|
+ this.setUnMeetFeeBatch(res.data.fees);
|
|
|
+ }
|
|
|
+ }).catch(() => {});
|
|
|
+ },
|
|
|
+ /** 拉取门店配送方式及说明(可选一并返回各 style 附加费预览) */
|
|
|
loadPsMethods() {
|
|
|
this.syncShopContext();
|
|
|
- return getAllPsMethod().then((res) => {
|
|
|
- if (res.code == 1 && res.data && Array.isArray(res.data.method)) {
|
|
|
- this.psMethodList = res.data.method;
|
|
|
+ const params = this.getUnMeetFeeBatchParams();
|
|
|
+ return getAllPsMethod(params).then((res) => {
|
|
|
+ if (res.code == 1 && res.data) {
|
|
|
+ if (Array.isArray(res.data.method)) {
|
|
|
+ this.psMethodList = res.data.method;
|
|
|
+ }
|
|
|
+ if (res.data.fees) {
|
|
|
+ this.setUnMeetFeeBatch(res.data.fees);
|
|
|
+ }
|
|
|
this.syncSendTypeAfterMethodsLoaded();
|
|
|
}
|
|
|
}).catch(() => {});
|
|
|
@@ -1154,7 +1196,7 @@ export default {
|
|
|
if (!this.selectedHbId) {
|
|
|
return;
|
|
|
}
|
|
|
- const price = Number(this.allPriceFun) || 0;
|
|
|
+ const price = Number(this.mixGoodsPrice) || 0;
|
|
|
const min = Number(this.selectedHb && this.selectedHb.minConsume) || 0;
|
|
|
if (price < min) {
|
|
|
this.selectedHbId = null;
|
|
|
@@ -1167,66 +1209,6 @@ export default {
|
|
|
this.form.cardInfo = "";
|
|
|
}
|
|
|
},
|
|
|
- /** 拼接最低消费门槛文案,如 200元或30扎 */
|
|
|
- buildUnMeetConditionText(method) {
|
|
|
- if (!method) {
|
|
|
- return "";
|
|
|
- }
|
|
|
- const parts = [];
|
|
|
- const minAmount = Number(method.minAmount) || 0;
|
|
|
- const minNum = Number(method.minNum) || 0;
|
|
|
- if (minAmount > 0) {
|
|
|
- parts.push(`${minAmount}元`);
|
|
|
- }
|
|
|
- if (minNum > 0) {
|
|
|
- parts.push(`${minNum}扎`);
|
|
|
- }
|
|
|
- return parts.join("或");
|
|
|
- },
|
|
|
- /**
|
|
|
- * 判断当前结算单是否未达最低消费
|
|
|
- * 满 minAmount 或 minNum 任一达标即视为达标;两者均未达标才返回 true
|
|
|
- */
|
|
|
- checkPsMethodBelowMinimum(method) {
|
|
|
- if (!method) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- const minAmount = Number(method.minAmount) || 0;
|
|
|
- const minNum = Number(method.minNum) || 0;
|
|
|
- if (minAmount <= 0 && minNum <= 0) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- const allPrice = Number(this.allPriceFun) || 0;
|
|
|
- const bigNum = Number(this.mixItemBigNum) || 0;
|
|
|
- const amountOk = minAmount <= 0 || allPrice >= minAmount;
|
|
|
- const numOk = minNum <= 0 || bigNum >= minNum;
|
|
|
- return !(amountOk || numOk);
|
|
|
- },
|
|
|
- /** 同步未达最低消费时的附加运费/包装费(与后端 PsMethodClass.calcFee 一致,按购买方式每日一次) */
|
|
|
- syncUnMeetFee() {
|
|
|
- const method = this.currentPsMethod;
|
|
|
- this.form.unMeetSendCost = 0;
|
|
|
- this.form.packCost = 0;
|
|
|
- if (!method || !this.checkPsMethodBelowMinimum(method)) {
|
|
|
- return;
|
|
|
- }
|
|
|
- const unMeet = Number(method.unMeet) || 0;
|
|
|
- const fee = parseFloat(Number(method.unMeetFee) || 0);
|
|
|
- if (fee <= 0) {
|
|
|
- return;
|
|
|
- }
|
|
|
- if (unMeet === 0) {
|
|
|
- if (Number(method.todaySendFeeLocked) === 1) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this.form.unMeetSendCost = fee;
|
|
|
- } else if (unMeet === 2) {
|
|
|
- if (Number(method.todayPackFeeLocked) === 1) {
|
|
|
- return;
|
|
|
- }
|
|
|
- this.form.packCost = fee;
|
|
|
- }
|
|
|
- },
|
|
|
onAnonymityChange(e) {
|
|
|
this.form.anonymity = e.detail.value ? 1 : 0;
|
|
|
},
|
|
|
@@ -1496,7 +1478,7 @@ export default {
|
|
|
this.deliveryQuotesLoading = false;
|
|
|
this.showDistance = 0;
|
|
|
}
|
|
|
- this.syncUnMeetFee();
|
|
|
+ this.applyCurrentUnMeetFee();
|
|
|
},
|
|
|
/** 构建跑腿报价请求中的收货地址(使用结算页所选地址坐标) */
|
|
|
buildDeliveryQuoteAddressPayload() {
|
|
|
@@ -1633,8 +1615,7 @@ export default {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- const method = this.currentPsMethod;
|
|
|
- if (method && Number(method.unMeet) === 1 && this.checkPsMethodBelowMinimum(method)) {
|
|
|
+ if (this.unMeetFeePreview && this.unMeetFeePreview.canOrder === false) {
|
|
|
this.$msg(this.unMeetWarningText || "未达到最低消费,不能下单");
|
|
|
return false;
|
|
|
}
|