|
|
@@ -253,6 +253,108 @@ export default {
|
|
|
}
|
|
|
return element.id == item.id && element.classId == item.classId;
|
|
|
},
|
|
|
+ // ----------- 购物车价格同步(修复 storage 旧缓存缺 reachPrice 导致确认页 ¥0)-----------
|
|
|
+ /**
|
|
|
+ * 扁平化当前页花材目录,供购物车价格同步使用
|
|
|
+ * V2 接口优先用 itemList;V1 从分类 child 展开
|
|
|
+ */
|
|
|
+ _getCatalogFlatList() {
|
|
|
+ // ghs-item-v2 返回的扁平列表,含 reachPrice 等最新价格字段
|
|
|
+ if (Array.isArray(this.globalItemList) && this.globalItemList.length > 0) {
|
|
|
+ return this.globalItemList;
|
|
|
+ }
|
|
|
+ const list = [];
|
|
|
+ const productInfo = this.productInfo;
|
|
|
+ if (!Array.isArray(productInfo)) {
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+ // ghs-item 按分类嵌套,需遍历 child 拼成 id 索引表
|
|
|
+ productInfo.forEach(cls => {
|
|
|
+ if (cls && Array.isArray(cls.child)) {
|
|
|
+ cls.child.forEach(item => {
|
|
|
+ if (item && item.id != null) {
|
|
|
+ list.push(item);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return list;
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 用最新花材目录补全购物车价格字段
|
|
|
+ * 解决 localStorage 旧缓存缺少 reachPrice 导致确认页显示 ¥0 的问题
|
|
|
+ * 仅覆盖价格/展示相关字段,不覆盖 bigCount、smallCount、autoPrice
|
|
|
+ * @param {Array} cachedList 购物车行(可能来自 vuex 或 storage)
|
|
|
+ * @returns {Array} 补全价格字段后的购物车
|
|
|
+ */
|
|
|
+ syncSelectListCatalogPrices(cachedList) {
|
|
|
+ if (!Array.isArray(cachedList) || cachedList.length === 0) {
|
|
|
+ return cachedList;
|
|
|
+ }
|
|
|
+ // 门店开单等非采购场景不走目录同步,避免误改其它业务购物车
|
|
|
+ if (!this._shouldMergeSelectByProductId()) {
|
|
|
+ return cachedList;
|
|
|
+ }
|
|
|
+ const catalog = this._getCatalogFlatList();
|
|
|
+ // 花材列表尚未加载完成时,保持原数据,等待下次 init 或提交前再同步
|
|
|
+ if (!catalog.length) {
|
|
|
+ return cachedList;
|
|
|
+ }
|
|
|
+ const catalogMap = new Map();
|
|
|
+ catalog.forEach(item => {
|
|
|
+ catalogMap.set(String(item.id), item);
|
|
|
+ });
|
|
|
+ // 允许从接口覆盖的字段:价格、满减、展示信息;不含用户操作类字段
|
|
|
+ const catalogSyncKeys = [
|
|
|
+ 'price', 'bigPrice', 'smallPrice', 'prePrice',
|
|
|
+ 'reachNum', 'reachNumDiscount', 'reachPrice',
|
|
|
+ 'discountPrice', 'hjPrice', 'skPrice', 'hjDiscountPrice', 'skDiscountPrice',
|
|
|
+ 'name', 'itemName', 'cover', 'weight', 'ratio', 'bigUnit', 'smallUnit',
|
|
|
+ 'ratioType', 'smallRatio', 'stock', 'bigNum', 'smallNum',
|
|
|
+ 'presell', 'limitBuy', 'itemRemark', 'variety'
|
|
|
+ ];
|
|
|
+ return cachedList.map(row => {
|
|
|
+ const fresh = catalogMap.get(String(row.id));
|
|
|
+ // 商品已下架或目录中找不到:保留原行,避免静默丢单
|
|
|
+ if (!fresh) {
|
|
|
+ return row;
|
|
|
+ }
|
|
|
+ const patched = { ...row };
|
|
|
+ catalogSyncKeys.forEach(key => {
|
|
|
+ if (fresh[key] !== undefined && fresh[key] !== null) {
|
|
|
+ patched[key] = fresh[key];
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return patched;
|
|
|
+ });
|
|
|
+ },
|
|
|
+ /**
|
|
|
+ * 解析满减达标后的扎单价(reachPrice)
|
|
|
+ * 优先用接口/缓存;旧缓存缺失时本地重算,避免确认页单价显示 ¥0
|
|
|
+ * 计算规则与后端 ProductClass::hdCgGroup 一致:原价减 reachNumDiscount,最低 0.01
|
|
|
+ * @param {Object} item 购物车中的花材行
|
|
|
+ * @returns {number} 满减后大单位单价
|
|
|
+ */
|
|
|
+ _resolveReachPrice(item) {
|
|
|
+ const reachNum = Number(item.reachNum) || 0;
|
|
|
+ // 未配置满减门槛,直接返回缓存值(通常为 0)
|
|
|
+ if (reachNum <= 0) {
|
|
|
+ return this.toSafeNumber(item.reachPrice);
|
|
|
+ }
|
|
|
+ const cached = Number(item.reachPrice);
|
|
|
+ // 缓存里已有有效满减价,优先信任接口最新值
|
|
|
+ if (!isNaN(cached) && cached > 0) {
|
|
|
+ return cached;
|
|
|
+ }
|
|
|
+ // 旧缓存仅有 reachNum / reachNumDiscount,缺少 reachPrice 时的兜底重算
|
|
|
+ const original = this.toSafeNumber(item.bigPrice || item.price);
|
|
|
+ const discount = Number(item.reachNumDiscount) || 0;
|
|
|
+ if (discount <= 0) {
|
|
|
+ return original;
|
|
|
+ }
|
|
|
+ const computed = Math.round((original - discount) * 100) / 100;
|
|
|
+ return computed <= 0 ? 0.01 : computed;
|
|
|
+ },
|
|
|
// ------------end---------
|
|
|
|
|
|
getLimitBuyItemById(id) {
|
|
|
@@ -273,6 +375,7 @@ export default {
|
|
|
const itemInfo = this.getSelectItemById(item.id, item.classId);
|
|
|
return Number(itemInfo.bigCount) >= reachNum;
|
|
|
},
|
|
|
+ // 满减优惠总额,确认页底部「省 ¥X」使用
|
|
|
getReachDiscountAmount(item) {
|
|
|
if (!this.isReachDiscountReached(item)) {
|
|
|
return 0;
|
|
|
@@ -280,13 +383,14 @@ export default {
|
|
|
const itemInfo = this.getSelectItemById(item.id, item.classId);
|
|
|
const bigCount = Number(itemInfo.bigCount) || 0;
|
|
|
const originalBig = this.toSafeNumber(item.bigPrice || item.price);
|
|
|
- const reachPrice = this.toSafeNumber(item.reachPrice);
|
|
|
+ const reachPrice = this._resolveReachPrice(item);
|
|
|
return Math.round(Math.max(0, bigCount * (originalBig - reachPrice)) * 100) / 100;
|
|
|
},
|
|
|
getCartItemUnitPrice(item) {
|
|
|
const itemInfo = this.getSelectItemById(item.id, item.classId);
|
|
|
+ // 满减达标后展示/计价用 reachPrice,须走统一解析避免旧缓存为 0
|
|
|
if (Number(itemInfo.bigCount) > 0 && this.isReachDiscountReached(item)) {
|
|
|
- return parseFloat(this.toSafeNumber(item.reachPrice));
|
|
|
+ return parseFloat(this._resolveReachPrice(item));
|
|
|
}
|
|
|
return parseFloat(this.toSafeNumber(item.bigPrice || item.price));
|
|
|
},
|
|
|
@@ -301,7 +405,8 @@ export default {
|
|
|
const bigCount = Number(itemInfo.bigCount) || 0;
|
|
|
const smallCount = Number(itemInfo.smallCount) || 0;
|
|
|
if (!result.isLimitSpecial) {
|
|
|
- const reachPrice = this.toSafeNumber(item.reachPrice);
|
|
|
+ // 普通满减:扎数 × 满减后单价 + 支数 × 小单位价
|
|
|
+ const reachPrice = this._resolveReachPrice(item);
|
|
|
const smallPrice = this.toSafeNumber(item.smallPrice);
|
|
|
result.total = bigCount * reachPrice + smallCount * smallPrice;
|
|
|
} else {
|
|
|
@@ -359,8 +464,9 @@ export default {
|
|
|
const priceInfo = this.getLimitBuyPriceInfo(item);
|
|
|
const fmt = (n) => parseFloat(Number(n) || 0);
|
|
|
const itemInfo = this.getSelectItemById(item.id, item.classId);
|
|
|
+ // 满减达标且非限购特价:主价显示满减单价,原价划线
|
|
|
if (priceInfo.reachDiscountActive && !priceInfo.isLimitSpecial && Number(itemInfo.bigCount) > 0) {
|
|
|
- const reachPrice = fmt(item.reachPrice);
|
|
|
+ const reachPrice = fmt(this._resolveReachPrice(item));
|
|
|
const originalBig = fmt(item.bigPrice || item.price);
|
|
|
return {
|
|
|
showStrike: reachPrice < originalBig,
|
|
|
@@ -473,8 +579,11 @@ export default {
|
|
|
let targetId = this.option.id ? this.option.id : 0
|
|
|
let currentInfo = uni.getStorageSync('selectList'+this.pageType+'_ghs_'+targetId)
|
|
|
if(!this.$util.isEmpty(currentInfo)){
|
|
|
+ // 恢复记忆购物车:合并重复行 → 用最新目录补价格 → 写回 storage 修复旧缓存
|
|
|
const mergedInfo = this._mergeDuplicateSelectRows(currentInfo);
|
|
|
- this.setSelectInfoByType({ type: this.pageType, info: mergedInfo })
|
|
|
+ const syncedInfo = this.syncSelectListCatalogPrices(mergedInfo);
|
|
|
+ this.setSelectInfoByType({ type: this.pageType, info: syncedInfo });
|
|
|
+ this.rememberProduct();
|
|
|
}else{
|
|
|
//临时解决方案
|
|
|
this.resetSelectInfoByType(this.pageType);
|
|
|
@@ -499,8 +608,11 @@ export default {
|
|
|
let targetId = this.option.id ? this.option.id : 0
|
|
|
let currentInfo = uni.getStorageSync('selectList'+this.pageType+'_ghs_'+targetId)
|
|
|
if(!this.$util.isEmpty(currentInfo)){
|
|
|
+ // 与 initGhsDataV2 相同:恢复时同步最新价格字段
|
|
|
const mergedInfo = this._mergeDuplicateSelectRows(currentInfo);
|
|
|
- this.setSelectInfoByType({ type: this.pageType, info: mergedInfo })
|
|
|
+ const syncedInfo = this.syncSelectListCatalogPrices(mergedInfo);
|
|
|
+ this.setSelectInfoByType({ type: this.pageType, info: syncedInfo });
|
|
|
+ this.rememberProduct();
|
|
|
}else{
|
|
|
//临时解决方案
|
|
|
this.resetSelectInfoByType(this.pageType);
|