|
|
@@ -52,8 +52,6 @@ export default {
|
|
|
}
|
|
|
},
|
|
|
|
|
|
- onUnload() {},
|
|
|
-
|
|
|
computed: {
|
|
|
...mapGetters(["getSelectInfo", "getLimitBuyInfo"]),
|
|
|
//当前页面选中的商品列表
|
|
|
@@ -417,6 +415,67 @@ export default {
|
|
|
}
|
|
|
return this.getLimitBuyPriceInfo(item).total;
|
|
|
},
|
|
|
+ /**
|
|
|
+ * 购物车中与目标花束行匹配的已有数量(按 id + 规格 + 活动类型分行)
|
|
|
+ * @param {Object} row 待匹配的购物车行结构
|
|
|
+ * @returns {Number} 已有 bigCount 合计
|
|
|
+ */
|
|
|
+ getMatchedBouquetCartCount(row) {
|
|
|
+ if (!row) return 0;
|
|
|
+ const list = Array.isArray(this.selectList) ? this.selectList : [];
|
|
|
+ let count = 0;
|
|
|
+ for (let i = 0; i < list.length; i++) {
|
|
|
+ if (this._selectRowMatches(list[i], row)) {
|
|
|
+ count += Number(list[i].bigCount) || 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return count;
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 校验花束本次数量是否超过商品库存 / 秒杀活动库存 / 秒杀限购。
|
|
|
+ * 不计入客户历史已购(当前没有该数据);existingCount 用于加购合并购物车已有件数。
|
|
|
+ * @param {Object} goods 带 stock / activityType / activityLimit / activityStock 的商品或购物车行
|
|
|
+ * @param {Number} buyNum 本次数量
|
|
|
+ * @param {Number} existingCount 购物车已有数量,立即购买传 0
|
|
|
+ * @returns {boolean} 是否通过
|
|
|
+ */
|
|
|
+ assertBouquetBuyQty(goods, buyNum, existingCount = 0) {
|
|
|
+ if (!goods) return false;
|
|
|
+ const num = Number(buyNum) || 0;
|
|
|
+ const exist = Number(existingCount) || 0;
|
|
|
+ const total = exist + num;
|
|
|
+ const stockRaw = goods.stock;
|
|
|
+ const hasStock = stockRaw !== undefined && stockRaw !== null && stockRaw !== '';
|
|
|
+ const stock = Number(stockRaw);
|
|
|
+ const stockSet = Number(goods.stockSet);
|
|
|
+ // 开启库存限制必须校验;未开启时仅在库存是有效数字时校验(避免列表商品缺 stock 被误拦)
|
|
|
+ if (stockSet === 1) {
|
|
|
+ if (!isFinite(stock) || !(stock > 0) || total > stock) {
|
|
|
+ this.$msg('库存不足哦');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ } else if (hasStock && isFinite(stock)) {
|
|
|
+ if (!(stock > 0) || total > stock) {
|
|
|
+ this.$msg('库存不足哦');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (goods.activityType === 'seckill') {
|
|
|
+ const actStockRaw = goods.activityStock;
|
|
|
+ const hasActStock = actStockRaw !== undefined && actStockRaw !== null && actStockRaw !== '';
|
|
|
+ const actStock = Number(actStockRaw) || 0;
|
|
|
+ if (hasActStock && (!(actStock > 0) || total > actStock)) {
|
|
|
+ this.$msg('库存不足哦');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ const limit = Number(goods.activityLimit) || 0;
|
|
|
+ if (limit > 0 && total > limit) {
|
|
|
+ this.$msg('超过限购数量,每人限购' + limit + '件');
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return true;
|
|
|
+ },
|
|
|
/**
|
|
|
* 组装花束购物车行(property=0):仅做校验并构造行结构,不写入 Vuex/缓存。
|
|
|
* 「立即购买」复用该行结构,保证与加购的计价、展示口径一致,同时不污染购物车。
|
|
|
@@ -443,11 +502,11 @@ export default {
|
|
|
this.$msg('商品还没有价格哦');
|
|
|
return null;
|
|
|
}
|
|
|
- const stock = Number(saleGoods.stock != null ? saleGoods.stock : goods.stock);
|
|
|
- if (stock <= 0 && Number(saleGoods.stockSet) === 1) {
|
|
|
- this.$msg('库存不足哦');
|
|
|
- return null;
|
|
|
- }
|
|
|
+ const stockRaw = saleGoods.stock != null ? saleGoods.stock : goods.stock;
|
|
|
+ const stockNum = Number(stockRaw);
|
|
|
+ const stockSet = Number(saleGoods.stockSet != null ? saleGoods.stockSet : goods.stockSet) || 0;
|
|
|
+ // 未开启库存限制且没有有效库存时,用 9999 占位,与后端 stockSet=0 的写法一致
|
|
|
+ const stock = isFinite(stockNum) ? stockNum : (stockSet === 1 ? 0 : 9999);
|
|
|
const row = {
|
|
|
id: goods.id,
|
|
|
goodsId: goods.id,
|
|
|
@@ -465,6 +524,7 @@ export default {
|
|
|
freightType: goods.freightType,
|
|
|
weight: saleGoods.weight != null ? saleGoods.weight : (goods.weight || 0),
|
|
|
stock: stock,
|
|
|
+ stockSet: stockSet,
|
|
|
bigNum: stock > 0 ? stock : 9999,
|
|
|
smallNum: 0,
|
|
|
bigCount: buyNum,
|
|
|
@@ -479,6 +539,15 @@ export default {
|
|
|
row.activityType = 'seckill';
|
|
|
row.activityEndTime = Number(goods.activityEndTime) || 0;
|
|
|
row.originPrice = Number(goods.originPrice) || 0;
|
|
|
+ row.activityLimit = Number(goods.activityLimit) || 0;
|
|
|
+ // 仅在明确带了活动库存时写入,避免列表加购缺该字段时被当成售罄
|
|
|
+ if (goods.activityStock !== undefined && goods.activityStock !== null && goods.activityStock !== '') {
|
|
|
+ row.activityStock = Number(goods.activityStock) || 0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 立即购买按本次数量校验;加购合并数量在 addBouquetToCart 里再验一次
|
|
|
+ if (!this.assertBouquetBuyQty(row, buyNum, 0)) {
|
|
|
+ return null;
|
|
|
}
|
|
|
return row;
|
|
|
},
|
|
|
@@ -494,6 +563,11 @@ export default {
|
|
|
return false;
|
|
|
}
|
|
|
const buyNum = Number(row.bigCount) || 1;
|
|
|
+ const existing = this.getMatchedBouquetCartCount(row);
|
|
|
+ // 加购要合并购物车已有件数后再验库存/限购,避免分次加购绕过秒杀限购
|
|
|
+ if (!this.assertBouquetBuyQty(row, buyNum, existing)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
const list = Array.isArray(this.selectList) ? [...this.selectList] : [];
|
|
|
let found = false;
|
|
|
for (let i = 0; i < list.length; i++) {
|