Эх сурвалжийг харах

花卉宝端(mallApp)--订单详情面(affirmGhs.vue)修改商品列表展示与 allPriceFun 计算逻辑变更

shizhongqi 2 сар өмнө
parent
commit
dccd81d96f

+ 200 - 27
mallApp/src/mixins/cgProduct.js

@@ -58,6 +58,10 @@ export default {
 		selectList() {
 			return this.getSelectInfo[this.pageType] || [];
 		},
+		//当前页面限购信息列表
+		limitBuyList() {
+			return this.getLimitBuyInfo[this.pageType] || [];
+		},
 		scrollClassId() {
 			const curClass = this.productInfo[this.classIndex];
 			if (curClass) {
@@ -88,17 +92,16 @@ export default {
 		},
 		allPriceFun() {
 			let price = 0;
+			if (this.selectList) {
+				// 唯一性处理,通过 id 去除重复商品 ---- 防止统计金额时因同一商品多次出现而重复计算
+				const newSelectList = this.selectList.filter(
+					(item, index, self) => index === self.findIndex(t => t.id === item.id)
+				);
 
-			if (this.list) {
-				for (const item of this.list) {
-					const itemInfo = this.getSelectItemById(item.id, item.classId);
-					if ( itemInfo && !this.$util.isEmpty(itemInfo.bigPrice) && !this.$util.isEmpty(itemInfo.smallPrice) ) {
-						price += item.bigCount * Number(itemInfo.bigPrice);
-						price += item.smallCount * Number(itemInfo.smallPrice);
-					}
+				for (const item of newSelectList) {
+					price += this.getLimitBuyPriceInfo(item).total;
 				}
 			}
-
 			return Math.round(price * 100) / 100;
 		},
 		//选择商品总数和总重要
@@ -130,13 +133,27 @@ export default {
 		allCountFun() {
 			let bigLength = 0;
 			let smallLength = 0;
-			if (this.list) {
-				for (const item of this.list) {
-					bigLength += item.bigCount
-					smallLength += item.smallCount
+			let weight = 0;
+			if (this.selectList) {
+				for (const item of this.selectList) {
+					bigLength += item.bigCount;
+					smallLength += item.smallCount;
+					if (item.weight) {
+						if (Number(item.bigCount) > 0) {
+							let bigAdd = Number(item.weight) * Number(item.bigCount);
+							weight = Number(weight) + Number(bigAdd);
+						} else {
+							let ratio = item.ratio || 20;
+							let unitWeight = item.weight / ratio;
+							let smallAdd = Number(unitWeight) * Number(item.smallCount);
+							weight = Number(weight) + Number(smallAdd);
+						}
+						weight = weight.toFixed(2);
+						weight = parseFloat(weight);
+					}
 				}
 			}
-			return {bigLength:bigLength,smallLength:smallLength,};
+			return { bigLength, smallLength, weight };
 		},
 		//描点-定位分类
 		suitScrollClassId() {
@@ -214,6 +231,156 @@ export default {
 			"setLimitBuyInfoByType",
 			"resetLimitBuyInfoByType"
 		]),
+		isTrueValue(value) {
+			return value === true || value === 1 || value === "1";
+		},
+		toSafeNumber(value) {
+			const num = Number(value);
+			return isNaN(num) ? 0 : num;
+		},
+		/** 供货商--采购 / 预订:列表里同一花材可能在不同分类下 classId 不同,购物车应按 id 合并为一行 */
+		_shouldMergeSelectByProductId() {
+			return this.pageType === "cg" || this.pageType === "bookCg";
+		},
+		_mergeDuplicateSelectRows(list) {
+			if (!Array.isArray(list) || list.length === 0) {
+				return Array.isArray(list) ? [...list] : [];
+			}
+			const map = new Map();
+			const order = [];
+			list.forEach(ele => {
+				const key = String(ele.id);
+				if (!map.has(key)) {
+					const copy = { ...ele };
+					copy.bigCount = Number(copy.bigCount) || 0;
+					copy.smallCount = Number(copy.smallCount) || 0;
+					map.set(key, copy);
+					order.push(key);
+				} else {
+					const prev = map.get(key);
+					prev.bigCount = Number(prev.bigCount) + (Number(ele.bigCount) || 0);
+					prev.smallCount = Number(prev.smallCount) + (Number(ele.smallCount) || 0);
+				}
+			});
+			return order.map(k => map.get(k));
+		},
+		_syncMergedSelectListIfNeeded() {
+			if (!this._shouldMergeSelectByProductId()) return;
+			const list = this.selectList;
+			if (!list || !list.length) return;
+			const merged = this._mergeDuplicateSelectRows(list);
+			if (merged.length !== list.length) {
+				this.setSelectInfoByType({ type: this.pageType, info: merged });
+			}
+		},
+		_selectRowMatches(element, item) {
+			if (!element || !item) return false;
+			if (this._shouldMergeSelectByProductId()) {
+				return String(element.id) === String(item.id);
+			}
+			return element.id == item.id && element.classId == item.classId;
+		},
+		getLimitBuyItemById(id) {
+			if (!Array.isArray(this.limitBuyList)) {
+				return null;
+			}
+			return this.limitBuyList.find(item => String(item.id) === String(id)) || null;
+		},
+		isLimitSpecialItem(item) {
+			const limitItem = this.getLimitBuyItemById(item.id);
+			return !!(limitItem && this.isTrueValue(limitItem.isLimit) && this.isTrueValue(limitItem.specialPrice));
+		},
+		getLimitBuyPriceInfo(item) {
+			const itemInfo = this.getSelectItemById(item.id, item.classId);
+
+			const specialPrice = this.toSafeNumber(item.price);
+			const originalPrice = this.toSafeNumber(item.prePrice);
+			const result = {
+				total: 0,
+				specialPrice: specialPrice,
+				originalPrice: originalPrice,
+				exceedNum: 0,
+				limitBuy: 0,
+				hasBuyNum: 0,
+				currentBuyNum: 0,
+				isLimitSpecial: false
+			};
+
+			result.total = itemInfo.bigCount * specialPrice + itemInfo.smallCount * originalPrice;
+			const limitItem = this.getLimitBuyItemById(item.id);
+			if (!limitItem || !this.isLimitSpecialItem(item)) {
+				return result;
+			}
+			const exceedNum = this.toSafeNumber(limitItem.exceedNum) + this.toSafeNumber(limitItem.currentBuyNum);
+			result.exceedNum = exceedNum;
+			result.limitBuy = this.toSafeNumber(limitItem.limitBuy);
+			result.hasBuyNum = this.toSafeNumber(limitItem.hasBuyNum);
+			result.currentBuyNum = this.toSafeNumber(limitItem.currentBuyNum);
+			result.isLimitSpecial = true;
+
+			if (result.exceedNum <= 0) {
+				result.total = result.currentBuyNum * specialPrice;
+			} else if (result.exceedNum > 0 && result.hasBuyNum > result.limitBuy) {
+				result.total = result.currentBuyNum * originalPrice;
+			} else {
+				result.total =
+					(result.currentBuyNum - result.exceedNum) * specialPrice + result.exceedNum * originalPrice;
+			}
+
+			return result;
+		},
+		getLimitBuyPriceDisplayParts(item) {
+			const priceInfo = this.getLimitBuyPriceInfo(item);
+			const fmt = n => parseFloat(Number(n) || 0);
+			if (!priceInfo.isLimitSpecial) {
+				const big = Number(item.bigCount) > 0;
+				const p = big ? this.toSafeNumber(item.bigPrice) : this.toSafeNumber(item.smallPrice);
+				return {
+					showStrike: false,
+					main: `¥${fmt(p)}`,
+					strike: ""
+				};
+			}
+			if (priceInfo.exceedNum <= 0) {
+				return {
+					showStrike: false,
+					main: `¥${fmt(priceInfo.specialPrice)}`,
+					strike: ""
+				};
+			}
+			if (priceInfo.exceedNum > 0 && priceInfo.hasBuyNum > priceInfo.limitBuy) {
+				return {
+					showStrike: false,
+					main: `¥${fmt(priceInfo.originalPrice)}`,
+					strike: ""
+				};
+			}
+			return {
+				showStrike: true,
+				main: `¥${fmt(priceInfo.specialPrice)}`,
+				strike: `¥${fmt(priceInfo.originalPrice)}`
+			};
+		},
+		getLimitBuyPriceText(item) {
+			const parts = this.getLimitBuyPriceDisplayParts(item);
+			if (parts.showStrike) {
+				return `${parts.main} ${parts.strike}`;
+			}
+			return parts.main;
+		},
+		getLimitBuyPriceTip(item) {
+			const priceInfo = this.getLimitBuyPriceInfo(item);
+			if (!priceInfo.isLimitSpecial) {
+				return "";
+			}
+			if (priceInfo.exceedNum <= 0) {
+				return `限购 ${priceInfo.limitBuy},未超限购,按特价计算`;
+			}
+			if (priceInfo.exceedNum > 0 && priceInfo.hasBuyNum > priceInfo.limitBuy) {
+				return `限购 ${priceInfo.limitBuy},已超出,按原价计算`;
+			}
+			return `限购 ${priceInfo.limitBuy},${priceInfo.currentBuyNum - priceInfo.exceedNum} 扎按特价,超出 ${priceInfo.exceedNum} 扎按原价`;
+		},
 		//记忆已选的花材
 		rememberProduct(){
 			//采购或预订的记忆花材
@@ -403,21 +570,27 @@ export default {
 				autoPrice: 0, //调价价格
 				itemPrice: 0 //调价价格
 			};
-			const item =
-				this.selectList &&
-				this.selectList.find(ele => {
-					return ele.id == id && ele.classId == classId;
-				});
-			if (item) {
-				info = {
-					...item,
-					bigCount: Number(item.bigCount),
-					smallCount: Number(item.smallCount),
-					autoPrice: Number(item.autoPrice),
-					itemPrice: Number(item.itemPrice),
-				};
+			if (!this.selectList || !this.selectList.length) {
+				return info;
 			}
-			return info;
+			const matches = this.selectList.filter(ele => this._selectRowMatches(ele, { id, classId }));
+			if (!matches.length) {
+				return info;
+			}
+			const base = { ...matches[0] };
+			let bigCount = 0;
+			let smallCount = 0;
+			matches.forEach(m => {
+				bigCount += Number(m.bigCount) || 0;
+				smallCount += Number(m.smallCount) || 0;
+			});
+			return {
+				...base,
+				bigCount,
+				smallCount,
+				autoPrice: Number(base.autoPrice),
+				itemPrice: Number(base.itemPrice)
+			};
 		},
 		//通过id获取当前选中的商品类别信息  左边菜单角标  当前选中该类别商品多少件
 		getSelectClassById(classId) {

+ 129 - 76
mallApp/src/pages/billing/affirmGhs.vue

@@ -5,25 +5,30 @@
 				<view class="module-com">
 					<view class="commodity-view">
 						<view class="commodity-list">
-							<view class="commodity-item" :class="{'limit-exceed-item': item._limitExceeded}" v-for="(item, index) in list" :key="index">
-								<image class="item-icon" :src="item.cover" />
+							<view class="commodity-item" :class="{'limit-exceed-item': isLimitExceededItem(item)}" v-for="(item, index) in list" :key="index">
+								<image class="item-icon" :src="item.cover" mode="aspectFill" />
 								<view class="item-info">
-									<view class="info-line">
+									<view class="item-row-top">
 										<text class="item-name">{{ item.name }}</text>
-										<text class="item-price">
-											<text class="price">
-												¥{{ parseFloat(item.bigPrice)||0 }}
-											</text>
-										</text>
+										<view class="item-price-block">
+											<text class="price-current">{{ affirmCommodityPriceParts[index].main }}</text>
+											<text v-if="affirmCommodityPriceParts[index].showStrike" class="price-original">{{ affirmCommodityPriceParts[index].strike }}</text>
+										</view>
+									</view>
+									<view class="item-row-ratio">
+										<text class="item-type" v-if="item.ratioType == 0">{{ item.ratio }}{{ item.smallUnit }}/{{ item.bigUnit }}</text>
+										<text class="item-type" v-else>若干{{ item.smallUnit }}/{{ item.bigUnit }}</text>
+									</view>
+									<view class="item-row-qty">
+										<text v-if="item.bigCount > 0" class="qty-part qty-big">{{ item.bigCount }}{{ item.bigUnit }}</text>
+										<text v-if="item.bigCount > 0 && item.smallCount > 0" class="qty-sep">·</text>
+										<text v-if="item.smallCount > 0" class="qty-part qty-small">{{ item.smallCount }}{{ item.smallUnit }}</text>
 									</view>
-									<view class="info-line">
-										<text class="item-type" v-if="item.ratioType == 0">{{item.ratio}}{{item.smallUnit}}/{{item.bigUnit}}</text>
-										<text class="item-type" v-else>若干{{item.smallUnit}}/{{item.bigUnit}}</text>
-										<text class="item-count">
-											<text>{{`${item.bigCount}`}}{{item.bigUnit}}</text>
-										</text>
+									<view v-if="isLimitExceededItem(item) || getLimitBuyPriceTip(item) || item.presell == 1" class="item-row-tips">
+										<text v-if="isLimitExceededItem(item)" class="limit-exceed-tip">限购 {{ limitExceedLimitBuy }},超出 {{ limitExceedNum }}</text>
+										<text v-if="getLimitBuyPriceTip(item)" class="limit-buy-price-tip">{{ getLimitBuyPriceTip(item) }}</text>
+										<text v-if="item.presell == 1" class="presell-tip">预售花材下单不能退款</text>
 									</view>
-									<text v-if="item._limitExceeded" class="limit-exceed-tip">限购 {{ limitExceedLimitBuy }},超出 {{ limitExceedNum }}</text>
 								</view>
 							</view>
 						</view>
@@ -31,7 +36,9 @@
 							<view class="operate-view" @click="modifyItem">
 								<text class="iconfont icongouwuche"></text>返回修改
 							</view>
-							<view class="describe-view">{{ allCount.bigLength }}扎,{{allCount.weight}}公斤,<text class="price">¥{{ allPriceFun }}</text></view>
+							<view class="describe-view">
+								<text class="price">共{{ allCountFun.bigLength }}扎,{{ allCountFun.weight }}公斤,合计 ¥{{ allPriceFun }}</text>
+							</view>
 						</view>
 					</view>
 				</view>
@@ -350,6 +357,7 @@ export default {
 		}
 	},
 	onShow() {
+		this._syncMergedSelectListIfNeeded();
 		let selectList = this.$util.copyObject(this.selectList); // selectList 来自 cgProduct.js 的 selectList
 		let mergedMap = {};
 		let list = [];
@@ -361,7 +369,6 @@ export default {
 				mergedMap[key].smallCount = mergedMap[key].smallCount + item.smallCount;
 			} else {
 				mergedMap[key] = this.$util.copyObject(item);
-				mergedMap[key]._limitExceeded = false
 				list.push(mergedMap[key]);
 			}
 		}
@@ -372,6 +379,11 @@ export default {
 		this.getHbData()
 	},
 	computed: {
+		/** 确认页列表每行价格展示(与 list 顺序一致) */
+		affirmCommodityPriceParts() {
+			const list = this.list || [];
+			return list.map(item => this.getLimitBuyPriceDisplayParts(item));
+		},
 		// 是否有可用红包
 		hasAvailableHb() {
 			if(!this.hbData || this.hbData.length === 0){
@@ -384,7 +396,7 @@ export default {
 			})
 		},
 		modifyPrice(){
-			let price = Number(this.allPrice) || 0
+			let price = Number(this.allPriceFun) || 0
 
 			// 减去红包金额
 			if(this.hasAvailableHb && this.selectedHbId){
@@ -415,7 +427,7 @@ export default {
 			return false
 		},
 		totalPrice() {
-			let allPrice = this.allPrice.toFixed(2)
+			let allPrice = this.allPriceFun.toFixed(2)
 			allPrice = Number(allPrice)
 			let price = allPrice
 
@@ -821,7 +833,6 @@ export default {
 			buyItem(params).then(res => {
 				uni.hideLoading()
 				if(res.code && res.code == 1){
-					this.clearLimitExceededMark()
 					this.limitExceedProductId = ''
 					this.limitExceedLimitBuy = ''
 					this.limitExceedNum = ''
@@ -835,11 +846,9 @@ export default {
 					this.limitExceedProductId = res.data.productId ? String(res.data.productId) : ''
 					this.limitExceedLimitBuy = res.data.limitBuy ? String(res.data.limitBuy) : '0'
 					this.limitExceedNum = res.data.exceed ? String(res.data.exceed) : '0'
-					this.markLimitExceededItem(this.limitExceedProductId)
 					this.$msg(res.msg || '累计已超出限购数')
 					return false
 				}else{
-					this.clearLimitExceededMark()
 					this.limitExceedProductId = ''
 					this.limitExceedLimitBuy = ''
 					this.limitExceedNum = ''
@@ -858,25 +867,6 @@ export default {
 			let hdId = this.option.hdId ? this.option.hdId : 0
 			this.$util.pageTo({url:'/pages/item/item?account='+account+'&hdId='+hdId,type:2})
 		},
-		markLimitExceededItem(productId){
-			if(!productId || !Array.isArray(this.list) || this.list.length <= 0){
-				return
-			}
-			const targetId = String(productId)
-			this.list.forEach((item, index) => {
-				const matched = String(item.id) === targetId
-				this.$set(this.list[index], '_limitExceeded', matched)
-			})
-			this.$forceUpdate()
-		},
-		clearLimitExceededMark(){
-			if(!Array.isArray(this.list) || this.list.length <= 0){
-				return
-			}
-			this.list.forEach((item, index) => {
-				this.$set(this.list[index], '_limitExceeded', false)
-			})
-		},
 		isLimitExceededItem(item){
 			if(!item || !this.limitExceedProductId){
 				return false
@@ -1085,50 +1075,113 @@ export default {
 						flex-shrink: 0;
 						width: 140upx;
 						height: 140upx;
+						border-radius: 4upx;
+						background-color: #f5f5f5;
 					}
 					.item-info {
-						position: relative;
 						display: flex;
 						flex-direction: column;
-						justify-content: center;
+						justify-content: flex-start;
 						flex: 1;
 						margin-left: 20upx;
-						.limit-exceed-tip {
+						min-width: 0;
+						.item-row-top {
+							display: flex;
+							flex-direction: row;
+							align-items: center;
+							justify-content: space-between;
+							width: 100%;
+						}
+						.item-name {
+							flex: 1;
+							min-width: 0;
+							padding-right: 16upx;
+							color: #333333;
+							font-size: 30upx;
+							font-weight: bold;
+							overflow: hidden;
+							white-space: nowrap;
+							text-overflow: ellipsis;
+							line-height: 1.3;
+						}
+						.item-price-block {
+							flex-shrink: 0;
+							display: flex;
+							flex-direction: row;
+							align-items: baseline;
+							max-width: 48%;
+						}
+						.price-current {
+							font-size: 32upx;
+							font-weight: bold;
+							color: #333333;
+							white-space: nowrap;
+							line-height: 1.2;
+						}
+						.price-original {
+							margin-left: 12upx;
+							font-size: 26upx;
+							color: #999999;
+							text-decoration: line-through;
+							white-space: nowrap;
+							line-height: 1.2;
+						}
+						.item-row-ratio {
+							margin-top: 8upx;
+							width: 100%;
+						}
+						.item-type {
+							color: #999999;
+							font-size: 24upx;
+							line-height: 1.4;
+						}
+						.item-row-qty {
+							display: flex;
+							flex-direction: row;
+							justify-content: flex-end;
+							align-items: center;
 							margin-top: 10upx;
+							flex-wrap: wrap;
+						}
+						.qty-sep {
+							margin: 0 8upx;
+							color: #cccccc;
+							font-size: 28upx;
+						}
+						.qty-part {
+							font-size: 28upx;
+							color: #666666;
+						}
+						.qty-big {
+							font-size: 30upx;
+							font-weight: bold;
+							color: #3385ff;
+						}
+						.item-row-tips {
+							display: flex;
+							flex-direction: column;
+							margin-top: -20upx;
+						}
+						.limit-exceed-tip {
+							margin-top: 4upx;
 							color: #ff4d4f;
 							font-size: 24upx;
 							font-weight: bold;
+							line-height: 1.45;
 						}
-						.info-line {
-							margin-bottom: 20upx;
-							display: flex;
-							justify-content: space-between;
-							align-items: flex-end;
-							.item-name {
-								color: #333333;
-								font-size: 32upx;
-								font-weight:bold;
-								overflow: hidden;
-								white-space: nowrap;
-								text-overflow: ellipsis;
-								width:400upx;
-							}
-							.item-price {
-								color: #333;
-								font-size: 22upx;
-								.price {
-									font-size: 30upx;
-									font-weight: bold;
-								}
-							}
-							.item-type {
-								color: #999;
-								font-size: 24upx;
-							}
-							.item-count {
-								color: #333333;
-								font-size: 30upx;
-							}
+						.limit-buy-price-tip {
+							margin-top: 4upx;
+							color: #ff7a00;
+							font-size: 24upx;
+							font-weight: bold;
+							line-height: 1.45;
+						}
+						.presell-tip {
+							margin-top: 4upx;
+							color: #e53935;
+							font-size: 24upx;
+							font-weight: bold;
+							line-height: 1.45;
 						}
 					}
 				}
@@ -1155,10 +1208,10 @@ export default {
 					display: flex;
 					align-items: center;
 					color: #333;
-					font-size: 26upx;
+					font-size: 24upx;
 					.price {
 						font-weight: bold;
-						font-size: 36upx;
+						font-size: 30upx;
 					}
 				}
 			}