From a4b3ee325c7354579d495bc74a777e494e5ec38c Mon Sep 17 00:00:00 2001
From: quanwei <419654421@qq.com>
Date: Fri, 06 Feb 2026 18:18:44 +0800
Subject: [PATCH] 商品可以价格面议 选择走访时显示输入走访企业名 分会添加活动时要总会审核 分类添加人数限制,添加活动选择了填写人数限制的分类时活动名额下显示该分类人数限制为15 同一个企业30天内只能走访一次,在30天内走访同一个企业时提示该企业已被走访xx天后才可以从新走访

---
 mobile/pages/product/list/list.vue |  670 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 635 insertions(+), 35 deletions(-)

diff --git a/mobile/pages/product/list/list.vue b/mobile/pages/product/list/list.vue
index db587a0..40663bd 100644
--- a/mobile/pages/product/list/list.vue
+++ b/mobile/pages/product/list/list.vue
@@ -4,8 +4,9 @@
 			<view class="index-search-box index-search-box_re d-b-c" id="searchBox">
 				<view class="index-search index-search_re t-c flex-1">
 					<span class="icon iconfont icon-sousuo"></span>
-					<input type="text" v-model="search" class="flex-1 ml10 f26 gray3" value="" placeholder-class="f26 gray9"
-					 placeholder="搜索商品" confirm-type="search" @confirm="searchFunc()" />
+					<input type="text" v-model="search" class="flex-1 ml10 f26 gray3" value=""
+						placeholder-class="f26 gray9" placeholder="搜索商品" confirm-type="search"
+						@confirm="searchFunc()" />
 				</view>
 			</view>
 			<view class="inner-tab">
@@ -28,22 +29,23 @@
 						</view>
 					</view>
 				</view>
-				<view class="item"  @click="select_type()">
+				<!-- <view class="item"  @click="select_type()">
 					<view class="box" style="height: 100%;">
 						<image style="width: 36rpx;height: 36rpx;" :src="isLieBiao == true?'/static/shop/liebiao.png':'/static/shop/tubiao.png'"></image>
 					</view>
-				</view>
+				</view> -->
 			</view>
 		</view>
 		<view class="prodcut-list-wrap">
-			<scroll-view scroll-y="true" class="scroll-Y" :style="'height:' + scrollviewHigh + 'px;'" lower-threshold="50"
-			 @scrolltolower="scrolltolowerFunc">
+			<scroll-view scroll-y="true" class="scroll-Y" :style="'height:' + scrollviewHigh + 'px;'"
+				lower-threshold="50" @scrolltolower="scrolltolowerFunc">
 				<view :class="topRefresh?'top-refresh open':'top-refresh'">
 					<view class="circle" v-for="(circle,n) in 3" :key="n"></view>
 				</view>
 				<view class="shop_body" v-if="isLieBiao ==true">
-					<view class="shop_body_l_item" :class="index==listData.length-1?'noborder':''" v-for="(item,index) in listData"
-					 :key="index" @click="gotoList(item.product_id)" v-if="index_open_city==0 || (index_open_city==1 && isInArray2(city_supplier_ids,item.shop_supplier_id))">
+					<view class="shop_body_l_item" :class="index==listData.length-1?'noborder':''"
+						v-for="(item,index) in listData" :key="index" @click="gotoList(item.product_id)"
+						v-if="index_open_city==0 || (index_open_city==1 && isInArray2(city_supplier_ids,item.shop_supplier_id))">
 						<view>
 							<image :src="item.product_image" mode=""></image>
 						</view>
@@ -51,29 +53,61 @@
 							<view class="shop_body_l_item_info_title gray3 f32">{{item.product_name}}</view>
 							<view class="d-b-c pb10">
 								<view class="shop_body_l_item_info_price">
-									<view class="f24 shop_red">¥<text class="f32 fb">{{item.product_price}}</text></view>
+									<view class="f24 shop_red">¥<text class="f32 fb">{{item.product_price}}</text>
+									</view>
 								</view>
-								<view class="shop_body_l_item_info_others f22">
+								<!-- <view class="shop_body_l_item_info_others f22">
 									<view class="shop_body_l_item_info_others_sales">累计成交:{{item.product_sales}}笔</view>
-								</view>
+								</view> -->
 							</view>
 						</view>
 					</view>
 				</view>
 				<view class="shop_body2" v-if="isLieBiao ==false">
-					<view class="shop_body_t_item" :class="index % 2 == 0?'ml20 mr20':' mr20'" v-for="(item,index) in listData" :key="index"
-					 @click="gotoList(item.product_id)" v-if="index_open_city==0 || (index_open_city==1 && isInArray2(city_supplier_ids,item.shop_supplier_id))">
+					<view class="shop_body_t_item" :class="index % 2 == 0?'ml20 mr20':' mr20'"
+						v-for="(item,index) in listData" :key="index" @click="gotoList(item.product_id)"
+						v-if="index_open_city==0 || (index_open_city==1 && isInArray2(city_supplier_ids,item.shop_supplier_id))">
 						<image :src="item.product_image" mode=""></image>
 						<view class="shop_body_t_item_info">
 							<view class="shop_body_t_item_info_title f26">{{item.product_name}}</view>
-							<view class="shop_body_t_item_info_others f24 gray9 mt">
+							<!-- <view class="shop_body_t_item_info_others f24 gray9 mt">
 								<view class="shop_body_t_item_info_others_sales">累计成交:{{item.product_sales}}笔</view>
-							</view>
+							</view> -->
 							<view class="shop_body_t_item_info_price">
-								<view class="f20 redF6">¥<text class="f32">{{item.product_price}}</text></view>
-								<view class="f20 huaxianjia">¥<text class="24">{{item.line_price}}</text></view>
+								<view class="f20 redF6" v-if="item.is_price_negotiable">价格面议</view>
+								<template v-else>
+									<view class="f20 redF6">¥<text class="f32">{{item.product_price}}</text></view>
+									<view class="f20 huaxianjia">¥<text class="24">{{item.line_price}}</text></view>
+								</template>
 							</view>
-
+							<!-- 购物车操作组件 -->
+							<view class="cart-action">
+								<!-- 多规格商品显示选择规格按钮 -->
+								<view class="spec-select-btn" v-if="item.spec_type === 20"
+									@click.stop="showSpecPopup(item,index)">
+									<text>选择规格</text>
+									<!-- 购物车数量徽章 -->
+									<view class="cart-badge" v-if="(item.cart && item.cart.total_num > 0)">
+										<text class="cart-count">{{ item.cart.total_num || 0 }}</text>
+									</view>
+								</view>
+								<!-- 单规格商品显示购物车操作 -->
+								<template v-else>
+									<view class="cart-btn-add" v-if="!item.cart.total_num || item.cart.total_num <= 0"
+										@click.stop="addToCart(item,index)">
+										<text class="icon iconfont icon-jia"></text>
+									</view>
+									<view class="cart-number-controller" v-else>
+										<view class="cart-btn-sub" @click.stop="decreaseCart(item,index)">
+											<text class="icon iconfont icon-jian"></text>
+										</view>
+										<view class="cart-number">{{ item.cart.total_num }}</view>
+										<view class="cart-btn-add" @click.stop="increaseCart(item,index)">
+											<text class="icon iconfont icon-jia"></text>
+										</view>
+									</view>
+								</template>
+							</view>
 						</view>
 					</view>
 				</view>
@@ -84,6 +118,57 @@
 				</view>
 				<uni-load-more v-else :loadingType="loadingType"></uni-load-more>
 			</scroll-view>
+		</view><!-- 规格选择弹窗 -->
+		<view class="spec-popup" :class="specPopupVisible ? 'visible' : ''" @touchmove.stop.prevent="">
+			<view class="popup-mask" @click="closeSpecPopup"></view>
+			<view class="popup-content" v-if="selectedProduct">
+				<view class="popup-header">
+					<image :src="selectedProduct.product_image" mode="aspectFit"></image>
+					<view class="popup-header-info">
+						<view class="price">¥{{ currentPrice }}</view>
+						<view class="stock">库存:{{ currentStock }}</view>
+						<view class="selected-spec">{{ selectedSpecText }}</view>
+					</view>
+					<view class="popup-header-right">
+						<view class="close-btn" @click="closeSpecPopup">
+							<text class="icon iconfont icon-guanbi"></text>
+						</view>
+					</view>
+				</view>
+
+				<view class="spec-section" v-if="selectedProduct.spec_type === 20 && selectedProduct.specData">
+					<view class="spec-group" v-for="(specGroup, groupIndex) in selectedProduct.specData.spec_attr"
+						:key="groupIndex">
+						<view class="spec-group-name">{{ specGroup.group_name }}</view>
+						<view class="spec-options">
+							<view class="spec-option"
+								:class="{ active: selectedSpecs[groupIndex] === specItem.item_id }"
+								v-for="(specItem, itemIndex) in specGroup.spec_items" :key="itemIndex"
+								@click="selectSpec(groupIndex, specItem.item_id)">
+								{{ specItem.spec_value }}
+							</view>
+						</view>
+					</view>
+				</view>
+
+				<view class="quantity-section">
+					<view class="quantity-label">数量</view>
+					<view class="quantity-controller">
+						<view class="quantity-btn" :class="{ disabled: quantity <= 1 }" @click="decreaseQuantity">
+							<text class="icon iconfont icon-jian"></text>
+						</view>
+						<view class="quantity-display">{{ quantity }}</view>
+						<view class="quantity-btn" :class="{ disabled: quantity >= currentStock }"
+							@click="increaseQuantity">
+							<text class="icon iconfont icon-jia"></text>
+						</view>
+					</view>
+				</view>
+
+				<view class="action-buttons">
+					<button class="add-cart-btn" @click="confirmAddToCart">加入购物车</button>
+				</view>
+			</view>
 		</view>
 	</view>
 </template>
@@ -96,7 +181,7 @@
 		},
 		data() {
 			return {
-				isLieBiao: true,
+				isLieBiao: false,
 				/*手机高度*/
 				phoneHeight: 0,
 				/*可滚动视图区域高度*/
@@ -121,8 +206,16 @@
 				sortPrice: 0,
 				list_rows: 10,
 				last_page: 0,
-				index_open_city:0,
-				city_supplier_ids:[],
+				index_open_city: 0,
+				city_supplier_ids: [],
+				// 购物车相关数据
+				cartData: {}, // 存储各商品在购物车中的数量
+
+				// 规格弹窗相关数据
+				specPopupVisible: false,
+				selectedProduct: null,
+				selectedSpecs: [],
+				quantity: 1,
 			};
 		},
 		computed: {
@@ -185,13 +278,13 @@
 					}
 				});
 			},
-			isInArray2(arr,value){
-				value=parseInt(value);
-			    var index = arr.indexOf(value);
-			    if(index >= 0){
-			        return true;
-			    }
-			    return false;
+			isInArray2(arr, value) {
+				value = parseInt(value);
+				var index = arr.indexOf(value);
+				if (index >= 0) {
+					return true;
+				}
+				return false;
 			},
 			/*还原初始化*/
 			restoreData() {
@@ -229,12 +322,12 @@
 			getData() {
 				let self = this;
 				var city_supplier_ids = '';
-				if(uni.getStorageSync('citySupplierRes')){
-					let resData=uni.getStorageSync('citySupplierRes');
-					self.city_supplier_ids=resData.supplier_ids;
+				if (uni.getStorageSync('citySupplierRes')) {
+					let resData = uni.getStorageSync('citySupplierRes');
+					self.city_supplier_ids = resData.supplier_ids;
 					city_supplier_ids = self.city_supplier_ids.join(",")
 				}
-				
+
 				let page = self.page;
 				let list_rows = self.list_rows;
 				let category_id = self.category_id;
@@ -249,12 +342,12 @@
 					sortType: sortType,
 					sortPrice: sortPrice,
 					list_rows: list_rows,
-					city_supplier_ids:city_supplier_ids
+					city_supplier_ids: city_supplier_ids
 				}, function(res) {
 					self.loading = false;
 					self.listData = self.listData.concat(res.data.list.data);
 					self.last_page = res.data.list.last_page;
-					self.index_open_city=res.data.store.index_open_city;
+					self.index_open_city = res.data.store.index_open_city;
 					if (res.data.list.last_page <= 1) {
 						self.no_more = true;
 					}
@@ -298,6 +391,256 @@
 					path: "/pages/product/category?" + this.getShareUrlParams()
 				};
 			},
+
+
+			// 添加到购物车或显示规格选择
+			addToCartOrShowSpec(product, index) {
+				if (product.spec_type === 20) {
+					// 多规格商品,显示规格选择弹窗
+					this.showSpecPopup(product);
+				} else {
+					// 单规格商品,直接添加到购物车
+					this.directlyAddToCart(product, index);
+				}
+			},
+
+			// 处理列表项购物车操作
+			handleListItemCartAction(product, index) {
+				// 如果是价格面议商品,提示联系客服
+				if (product.is_price_negotiable) {
+					uni.showModal({
+						title: '温馨提示',
+						content: '该商品为价格面议商品,请联系客服咨询具体价格',
+						confirmText: '联系客服',
+						cancelText: '取消',
+						success: (res) => {
+							if (res.confirm) {
+								// 这里可以跳转到客服页面或显示联系方式
+								uni.showToast({
+									title: '请联系客服咨询',
+									icon: 'none'
+								});
+							}
+						}
+					});
+				} else {
+					// 非价格面议商品,正常添加到购物车
+					this.directlyAddToCart(product, index);
+				}
+			},
+
+			// 添加到购物车(单规格商品)
+			addToCart(product, index) {
+				this.directlyAddToCart(product, index);
+			},
+
+			// 直接添加到购物车(单规格商品)
+			directlyAddToCart(product, index) {
+				this._post('order.cart/add', {
+					product_id: product.product_id,
+					total_num: 1,
+					spec_sku_id: 0
+				}, (res) => {
+					if (res.code === 1) {
+						if (!product.cart) {
+							product.cart = {
+								total_num: 0
+							}
+						}
+						// 更新商品的购物车数量
+						product.cart.total_num++;
+						this.listData[index].cart.total_num = product.cart.total_num;
+					} else {
+						uni.showToast({
+							title: res.msg,
+							icon: 'none'
+						});
+					}
+				});
+			},
+
+			// 显示规格选择弹窗
+			showSpecPopup(product) {
+				this.selectedProduct = product;
+				this.quantity = 1;
+				let url = ''
+				//#ifdef H5
+				if (this.isWeixin()) {
+					url = window.location.href;
+				}
+				//#endif
+				// 获取商品规格数据
+				this._get('product.product/detail', {
+					product_id: product.product_id,
+					url: url,
+					visitcode: this.getVisitcode()
+				}, (res) => {
+					if (res.code === 1) {
+
+						// 使用正确的路径获取规格数据
+						let specData = res.data.detail.product_multi_spec || res.data.detail;
+						this.$set(this.selectedProduct, 'specData', specData);
+						// 同时设置SKU数据
+						if (res.data.detail.sku) {
+							this.$set(this.selectedProduct, 'sku', res.data.detail.sku);
+						}
+						console.log(this.selectedSpecs);
+						// 初始化选中规格数组
+
+						if (specData && specData.spec_attr) {
+							this.selectedSpecs = specData.spec_attr.map(specGroup => {
+								return specGroup.spec_items && specGroup.spec_items.length > 0 ? specGroup
+									.spec_items[0].item_id : null;
+							});
+							this.specPopupVisible = true;
+
+						} else {
+							uni.showToast({
+								title: '获取商品规格失败',
+								icon: 'none'
+							});
+							return;
+						}
+
+					} else {
+						uni.showToast({
+							title: '获取商品规格失败',
+							icon: 'none'
+						});
+					}
+				});
+			},
+
+			// 关闭规格选择弹窗
+			closeSpecPopup() {
+				this.specPopupVisible = false;
+				this.selectedProduct = null;
+				this.selectedSpecs = [];
+			},
+
+			// 选择规格
+			selectSpec(groupIndex, itemId) {
+				// 使用 Vue.set 确保响应式更新
+				this.$set(this.selectedSpecs, groupIndex, itemId);
+			},
+
+			// 增加数量
+			increaseQuantity() {
+				if (this.quantity < this.currentStock) {
+					this.quantity++;
+				}
+			},
+
+			// 减少数量
+			decreaseQuantity() {
+				if (this.quantity > 1) {
+					this.quantity--;
+				}
+			},
+
+			// 确认添加到购物车
+			confirmAddToCart() {
+				// 检查是否选择了所有规格
+				if (this.selectedSpecs.includes(null) || this.selectedSpecs.includes(undefined)) {
+					uni.showToast({
+						title: '请选择完整的商品规格',
+						icon: 'none'
+					});
+					return;
+				}
+
+				// 构造规格SKU ID
+				const specSkuId = this.selectedSpecs.join('_');
+
+				this._post('order.cart/add', {
+					product_id: this.selectedProduct.product_id,
+					total_num: this.quantity,
+					spec_sku_id: specSkuId ? specSkuId : 0
+				}, (res) => {
+					if (res.code === 1) {
+						// 更新商品的购物车数量
+						const product = this.listData.find(p => p.product_id === this.selectedProduct
+							.product_id);
+						if (product) {
+							if (!product.cart) {
+								product.cart = {
+									total_num: 0
+								}
+							}
+							product.cart.total_num++;
+						}
+
+						// 关闭弹窗
+						this.closeSpecPopup();
+
+						uni.showToast({
+							title: '已添加到购物车',
+							icon: 'success'
+						});
+					} else {
+						uni.showToast({
+							title: res.msg,
+							icon: 'none'
+						});
+					}
+				});
+			},
+
+			// 增加购物车商品数量
+			increaseCart(product, index) {
+				this._post('order.cart/add', {
+					product_id: product.product_id,
+					total_num: 1,
+					spec_sku_id: 0
+				}, (res) => {
+					if (res.code === 1) {
+						product.cart.total_num++;
+						this.listData[index].cart.total_num = product.cart.total_num;
+					} else {
+						uni.showToast({
+							title: res.msg,
+							icon: 'none'
+						});
+					}
+				});
+			},
+
+			// 减少购物车商品数量
+			decreaseCart(product, index) {
+				if (product.cart.total_num <= 1) {
+					// 如果数量为1,执行删除操作
+					this._post('order.cart/delete', {
+						product_id: product.product_id,
+						cart_id: product.cart.cart_id,
+						spec_sku_id: product.product_sku.spec_sku_id
+					}, (res) => {
+						if (res.code === 1) {
+							this.listData[index].cart.total_num = 0;
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					});
+				} else {
+					// 否则减少数量
+					this._post('order.cart/sub', {
+						product_id: product.product_id,
+						spec_sku_id: product.product_sku.spec_sku_id
+					}, (res) => {
+						if (res.code === 1) {
+							product.cart.total_num--;
+							this.listData[index].cart.total_num = product.cart.total_num;
+						} else {
+							uni.showToast({
+								title: res.msg,
+								icon: 'none'
+							});
+						}
+					});
+				}
+			}
 		}
 	};
 </script>
@@ -602,4 +945,261 @@
 	.noborder {
 		border: none;
 	}
-</style>
+
+	//购物车
+	.cart-action {
+		display: flex;
+		justify-content: flex-end;
+	}
+
+	.cart-btn-add,
+	.cart-btn-sub {
+		width: 48rpx;
+		height: 48rpx;
+		border-radius: 50%;
+		background: #ff6b6b;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		color: white;
+		font-size: 24rpx;
+	}
+
+	.spec-select-btn {
+		padding: 2rpx 4rpx;
+		background: #ff6b6b;
+		color: white;
+		border-radius: 24rpx;
+		font-size: 24rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		min-width: 120rpx;
+		height: 48rpx;
+		position: relative;
+	}
+
+	.cart-btn-sub {
+		background: #f0f0f0;
+		color: #666;
+	}
+
+	.cart-number {
+		margin: 0 10rpx;
+		font-size: 28rpx;
+	}
+
+	.cart-number-controller {
+		display: flex;
+		align-items: center;
+	}
+
+	/* 规格选择弹窗样式 */
+	.spec-popup {
+		position: fixed;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		z-index: 1000;
+		visibility: hidden;
+		opacity: 0;
+		transition: all 0.3s ease;
+	}
+
+	.spec-popup.visible {
+		visibility: visible;
+		opacity: 1;
+	}
+
+	.popup-mask {
+		position: absolute;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		background: rgba(0, 0, 0, 0.6);
+	}
+
+	.popup-content {
+		position: absolute;
+		bottom: 0;
+		left: 0;
+		right: 0;
+		background: white;
+		border-top-left-radius: 20rpx;
+		border-top-right-radius: 20rpx;
+		padding: 30rpx;
+		transform: translateY(100%);
+		transition: transform 0.3s ease;
+		max-height: 80%;
+		overflow-y: auto;
+	}
+
+	.spec-popup.visible .popup-content {
+		transform: translateY(0);
+	}
+
+	.popup-header {
+		display: flex;
+		position: relative;
+		padding-right: 60rpx;
+		margin-bottom: 30rpx;
+	}
+
+	.popup-header image {
+		width: 160rpx;
+		height: 160rpx;
+		border-radius: 10rpx;
+	}
+
+	.popup-header-info {
+		margin-left: 20rpx;
+		flex: 1;
+	}
+
+	.price {
+		font-size: 36rpx;
+		color: #ff6b6b;
+		font-weight: bold;
+	}
+
+	.stock {
+		font-size: 24rpx;
+		color: #999;
+		margin-top: 10rpx;
+	}
+
+	.selected-spec {
+		font-size: 24rpx;
+		color: #666;
+		margin-top: 10rpx;
+	}
+
+	.popup-header-right {
+		position: absolute;
+		right: 0;
+		top: 0;
+		display: flex;
+		align-items: center;
+		gap: 20rpx;
+	}
+
+	.cart-badge {
+		position: absolute;
+		top: -12rpx;
+		right: -12rpx;
+		background: #ff4757;
+		color: white;
+		border-radius: 50%;
+		min-width: 32rpx;
+		height: 32rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		font-size: 20rpx;
+		line-height: 1;
+		padding: 0 6rpx;
+		z-index: 10;
+	}
+
+	.cart-count {
+		color: white;
+		font-size: 20rpx;
+		line-height: 1;
+	}
+
+	.close-btn {
+		width: 50rpx;
+		height: 50rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		color: #999;
+	}
+
+	.spec-section {
+		margin-bottom: 30rpx;
+	}
+
+	.spec-group {
+		margin-bottom: 30rpx;
+	}
+
+	.spec-group-name {
+		font-size: 28rpx;
+		font-weight: bold;
+		margin-bottom: 20rpx;
+	}
+
+	.spec-options {
+		display: flex;
+		flex-wrap: wrap;
+	}
+
+	.spec-option {
+		padding: 10rpx 20rpx;
+		border: 1rpx solid #ddd;
+		border-radius: 10rpx;
+		margin-right: 20rpx;
+		margin-bottom: 20rpx;
+		font-size: 26rpx;
+	}
+
+	.spec-option.active {
+		border-color: #ff6b6b;
+		color: #ff6b6b;
+	}
+
+	.quantity-section {
+		display: flex;
+		align-items: center;
+		justify-content: space-between;
+		margin-bottom: 30rpx;
+	}
+
+	.quantity-label {
+		font-size: 28rpx;
+	}
+
+	.quantity-controller {
+		display: flex;
+		align-items: center;
+	}
+
+	.quantity-btn {
+		width: 50rpx;
+		height: 50rpx;
+		border: 1rpx solid #ddd;
+		border-radius: 10rpx;
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		font-size: 24rpx;
+	}
+
+	.quantity-btn.disabled {
+		opacity: 0.5;
+	}
+
+	.quantity-display {
+		margin: 0 20rpx;
+		font-size: 28rpx;
+		min-width: 60rpx;
+		text-align: center;
+	}
+
+	.action-buttons {
+		text-align: center;
+	}
+
+	.add-cart-btn {
+		width: 100%;
+		height: 80rpx;
+		background: linear-gradient(90deg, #ff6b6b, #ff8e8e);
+		border-radius: 40rpx;
+		color: white;
+		font-size: 32rpx;
+		border: none;
+	}
+</style>
\ No newline at end of file

--
Gitblit v1.9.2