From cf2da3b2a63840888815c6a81cbd7948faf93533 Mon Sep 17 00:00:00 2001
From: doum <doum>
Date: 星期一, 08 六月 2026 17:41:15 +0800
Subject: [PATCH] aaa

---
 h5/pages/index_3/index.vue |  513 ++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 438 insertions(+), 75 deletions(-)

diff --git a/h5/pages/index_3/index.vue b/h5/pages/index_3/index.vue
index c748635..7a01d06 100644
--- a/h5/pages/index_3/index.vue
+++ b/h5/pages/index_3/index.vue
@@ -236,22 +236,41 @@
 											<text>{{ sub.name }}</text>
 										</view>
 									</view>
-									<view class="expand_search_wrap">
+									<view class="expand_search_wrap" :style="suggestDropdownTheme">
 										<view class="expand_search" :style="searchBarStyle">
 											<image class="search_icon" src="@/static/ic_search@2x.png" mode="aspectFit"></image>
-											<input type="text" v-model="row.modelVal" placeholder="鎼滅储鍟嗗搧鍚嶇О/鍨嬪彿" @input="searchModel(row)" />
+											<view class="search_divider"></view>
+											<input type="text" v-model="row.modelVal" placeholder="鎼滅储鍟嗗搧鍚嶇О/鍨嬪彿" placeholder-class="expand_search_placeholder" @input="searchModel(row)" />
 										</view>
-										<view class="model_suggest_list" v-if="hasModelKeyword(row) && modelOptions(row).length">
-											<view
-												class="model_suggest_item"
-												v-for="(g, gi) in modelOptions(row)"
-												:key="g.id || gi"
-												@click.stop="onClickSound(() => selectGoodsFromSearch(index, g))"
-												@mouseenter="playHoverSound">
-												{{ g.name }}
+										<view class="model_suggest_panel" v-if="hasModelKeyword(row) && modelOptions(row).length">
+											<view class="model_suggest_list">
+												<view
+													class="model_suggest_item"
+													v-for="(g, gi) in modelOptions(row)"
+													:key="g.id || gi"
+													@click.stop="onClickSound(() => selectGoodsFromSearch(index, g))"
+													@mouseenter="playHoverSound">
+													<view class="model_suggest_thumb">
+														<image v-if="suggestGoodsImg(g)" :src="suggestGoodsImg(g)" mode="aspectFit"></image>
+														<view v-else class="model_suggest_thumb_ph"></view>
+													</view>
+													<view class="model_suggest_body">
+														<text class="model_suggest_name">{{ g.name }}</text>
+														<text class="model_suggest_brand" v-if="g.brandName">{{ g.brandName }}</text>
+													</view>
+													<view class="model_suggest_meta">
+														<text class="model_suggest_price" v-if="g.price != null && g.price !== ''">楼{{ g.price }}</text>
+														<text class="model_suggest_zd" v-if="g.zdPrice != null && g.zdPrice !== ''">鏃楄埌 楼{{ g.zdPrice }}</text>
+													</view>
+												</view>
+											</view>
+											<view class="model_suggest_footer">
+												<text>鍏� {{ modelOptions(row).length }} 浠跺彲閫�</text>
 											</view>
 										</view>
-										<view class="model_suggest_empty" v-else-if="hasModelKeyword(row)">鏆傛棤鍖归厤鍟嗗搧</view>
+										<view class="model_suggest_empty" v-else-if="hasModelKeyword(row)">
+											<text class="model_suggest_empty_text">鏈壘鍒般�寋{ (row.modelVal || '').trim() }}銆嶇浉鍏冲晢鍝�</text>
+										</view>
 									</view>
 								</view>
 							</view>
@@ -266,12 +285,12 @@
 					<view class="product_grid">
 						<view
 							class="product_card"
-							v-for="(item, pi) in displayProducts"
+							v-for="(item, pi) in visibleProducts"
 							:key="item.id || pi"
 							@click="onClickSound(() => clickProduct(item))"
 							@mouseenter="playHoverSound">
 							<view class="product_card_img">
-								<image :src="productImg(item)" mode="aspectFit"></image>
+								<image :src="productImg(item)" mode="aspectFit" lazy-load></image>
 							</view>
 							<view class="product_card_info">
 								<text class="product_brand">{{ item.brandName || '' }}</text>
@@ -279,8 +298,20 @@
 								<text class="product_price_label">鎸囧浠� 楼 {{ item.price || '' }}</text>
 							</view>
 						</view>
-						<view class="product_card placeholder" v-if="!displayProducts.length">
+						<view class="product_card placeholder" v-if="!visibleProducts.length && !productLoadingMore">
 							<text>鏆傛棤鍟嗗搧</text>
+						</view>
+					</view>
+					<view class="product_list_footer" v-if="productTotalCount > 0">
+						<view class="product_load_hint" v-if="productLoadingMore">
+							<view class="product_load_spinner"></view>
+							<text>鍔犺浇涓�...</text>
+						</view>
+						<view class="product_load_hint" v-else-if="hasMoreProducts">
+							<text>宸叉樉绀� {{ visibleProducts.length }} / {{ productTotalCount }}锛岀户缁笂婊戝姞杞芥洿澶�</text>
+						</view>
+						<view class="product_load_hint product_load_hint--done" v-else>
+							<text>宸插姞杞藉叏閮� {{ productTotalCount }} 浠跺晢鍝�</text>
 						</view>
 					</view>
 				</view>
@@ -481,6 +512,7 @@
 const DEFAULT_MAIN = '#E8DCC8'
 const DEFAULT_HEADER = '#4A3728'
 const DEFAULT_ROW = '#FFFFFF'
+const PRODUCT_PAGE_SIZE = 30
 
 export default {
 	components: { search, bigImg },
@@ -526,6 +558,8 @@
 
 			shopPageData: [],
 			shopPageDataSou: [],
+			productPageNo: 1,
+			productLoadingMore: false,
 			shopPageBrand: { id: '', name: '' },
 			brandData: [],
 			title: '',
@@ -585,7 +619,26 @@
 			return { background: t.rowBg || DEFAULT_ROW }
 		},
 		dropdownStyle() {
-			return { background: this.themeStyle.background }
+			const { background, color } = this.themeStyle
+			const accent = this.accentColor || '#FFD88A'
+			return {
+				background,
+				color,
+				'--picker-accent': accent,
+				'--picker-hover-bg': 'rgba(255, 255, 255, 0.14)',
+				'--picker-active-bg': this.hexToRgba(accent, 0.28),
+				'--picker-divider': 'rgba(255, 255, 255, 0.12)'
+			}
+		},
+		suggestDropdownTheme() {
+			const { background } = this.themeStyle
+			const accent = this.accentColor || '#FFD88A'
+			return {
+				'--suggest-theme': background,
+				'--suggest-accent': accent,
+				'--suggest-accent-soft': this.hexToRgba(accent, 0.22),
+				'--suggest-theme-soft': this.hexToRgba(background, 0.08)
+			}
 		},
 		searchBarStyle() {
 			const s = (this.configuration && this.configuration.search) || {}
@@ -659,6 +712,16 @@
 		displayProducts() {
 			return Array.isArray(this.shopPageDataSou) ? this.shopPageDataSou : []
 		},
+		productTotalCount() {
+			return this.displayProducts.length
+		},
+		visibleProducts() {
+			const end = this.productPageNo * PRODUCT_PAGE_SIZE
+			return this.displayProducts.slice(0, end)
+		},
+		hasMoreProducts() {
+			return this.visibleProducts.length < this.productTotalCount
+		},
 		productListCategoryImg() {
 			const row = this.activeRowIndex >= 0 ? this.shopList[this.activeRowIndex] : null
 			return (row && row.categoryImgurl) ? row.categoryImgurl : ''
@@ -708,6 +771,33 @@
 		this.sessionCreateTime = new Date()
 		this.loadAllData()
 	},
+
+	onReachBottom() {
+		this.tryLoadMoreProducts()
+	},
+
+	mounted() {
+		if (typeof window !== 'undefined') {
+			this._onProductScroll = () => {
+				if (this.status !== 1 || !this.hasMoreProducts) return
+				const doc = document.documentElement
+				const scrollTop = doc.scrollTop || document.body.scrollTop || 0
+				const viewHeight = doc.clientHeight || window.innerHeight
+				const scrollHeight = doc.scrollHeight || document.body.scrollHeight
+				if (scrollTop + viewHeight >= scrollHeight - 100) {
+					this.tryLoadMoreProducts()
+				}
+			}
+			window.addEventListener('scroll', this._onProductScroll, { passive: true })
+		}
+	},
+
+	beforeDestroy() {
+		if (typeof window !== 'undefined' && this._onProductScroll) {
+			window.removeEventListener('scroll', this._onProductScroll)
+		}
+	},
+
 	methods: {
 		playHoverSound,
 		playClickSound,
@@ -992,6 +1082,11 @@
 			return row.modelSearchList || []
 		},
 
+		suggestGoodsImg(g) {
+			if (!g || !g.imgurl) return ''
+			return (g.prefixUrl || '') + g.imgurl
+		},
+
 		selectGoodsFromSearch(index, goods) {
 			this.applyGoodsToRow(index, goods)
 			this.hoverRowIndex = -1
@@ -1104,6 +1199,7 @@
 			if (!row) {
 				this.shopPageData = []
 				this.shopPageDataSou = []
+				this.resetProductPagination()
 				return
 			}
 			const list = filterGoods(this.allGoods, {
@@ -1136,9 +1232,24 @@
 			const kw = (this.title || '').trim()
 			if (!kw) {
 				this.shopPageDataSou = source.slice()
-				return
+			} else {
+				this.shopPageDataSou = source.filter(item => matchKeyword(item, kw))
 			}
-			this.shopPageDataSou = source.filter(item => matchKeyword(item, kw))
+			this.resetProductPagination()
+		},
+
+		resetProductPagination() {
+			this.productPageNo = 1
+			this.productLoadingMore = false
+		},
+
+		tryLoadMoreProducts() {
+			if (this.status !== 1 || !this.hasMoreProducts || this.productLoadingMore) return
+			this.productLoadingMore = true
+			this.$nextTick(() => {
+				this.productPageNo += 1
+				this.productLoadingMore = false
+			})
 		},
 
 		clickProduct(item) {
@@ -1423,6 +1534,7 @@
 			this.hoverRowIndex = -1
 			this.resetPkState()
 			this.title = ''
+			this.resetProductPagination()
 			this.shopPageData = []
 			this.shopPageDataSou = []
 			this.loadOrderNo()
@@ -1437,6 +1549,7 @@
 				this.status = 0
 				this.title = ''
 				this.showBrandPicker = false
+				this.resetProductPagination()
 				this.shopPageData = []
 				this.shopPageDataSou = []
 				this.activeRowIndex = -1
@@ -1935,41 +2048,76 @@
 	}
 }
 
-.home_top_section .category_picker {
-	position: absolute;
-	top: calc(100% + 2px);
-	left: -26px;
-	min-width: 168px;
-	z-index: 20;
-	max-height: 240px;
-	overflow-y: auto;
-	border-radius: 0 0 6px 6px;
-	padding: 6px 0;
-	box-shadow: 0 8px 20px rgba(0, 0, 0, 0.22);
+.home_top_section 	.category_picker {
+		position: absolute;
+		top: calc(100% + 6px);
+		left: -26px;
+		min-width: 188px;
+		z-index: 20;
+		max-height: 260px;
+		overflow-x: hidden;
+		overflow-y: auto;
+	border-radius: 12px;
+	padding: 0;
+	box-shadow: 0 12px 32px rgba(61, 46, 34, 0.28);
+	border: 1px solid rgba(255, 255, 255, 0.14);
+	backdrop-filter: blur(8px);
+
+	&::-webkit-scrollbar {
+		width: 4px;
+	}
+
+	&::-webkit-scrollbar-thumb {
+		background: rgba(255, 255, 255, 0.28);
+		border-radius: 999px;
+	}
+
+	&::before {
+		content: '';
+		display: block;
+		height: 3px;
+		background: var(--picker-accent, #FFD88A);
+		border-radius: 12px 12px 0 0;
+	}
 
 	.category_picker_item {
 		display: flex;
 		align-items: center;
 		gap: 10px;
-		padding: 10px 12px;
-		color: #fff;
+		padding: 11px 14px;
+		color: inherit;
 		cursor: pointer;
-		border-radius: 0;
+		border-bottom: 1px solid var(--picker-divider, rgba(255, 255, 255, 0.12));
+		transition: background 0.15s;
+
+		&:last-child {
+			border-bottom: none;
+		}
 
 		&:hover {
-			background: rgba(255, 255, 255, 0.1);
+			background: var(--picker-hover-bg, rgba(255, 255, 255, 0.14));
 		}
 
 		image {
-			width: 28px;
-			height: 28px;
+			width: 30px;
+			height: 30px;
+			border-radius: 6px;
+			background: rgba(255, 255, 255, 0.12);
+			padding: 2px;
+			box-sizing: border-box;
+		}
+
+		text {
+			font-size: 13px;
+			font-weight: 500;
+			line-height: 1.3;
 		}
 	}
 
 	.category_picker_empty {
-		padding: 16px;
+		padding: 20px 16px;
 		text-align: center;
-		color: rgba(255, 255, 255, 0.7);
+		color: rgba(255, 255, 255, 0.72);
 		font-size: 13px;
 	}
 }
@@ -2098,26 +2246,71 @@
 
 	.brand_picker {
 		position: absolute;
-		top: calc(100% + 4px);
+		top: calc(100% + 6px);
 		right: 0;
-		min-width: 120px;
-		max-height: 220px;
+		min-width: 136px;
+		max-height: 240px;
+		overflow-x: hidden;
 		overflow-y: auto;
-		border-radius: 8px;
-		padding: 6px 0;
-		box-shadow: 0 8px 20px rgba(0, 0, 0, 0.22);
+		border-radius: 12px;
+		padding: 0;
+		box-shadow: 0 12px 32px rgba(61, 46, 34, 0.28);
+		border: 1px solid rgba(255, 255, 255, 0.14);
 		z-index: 20;
+		backdrop-filter: blur(8px);
+
+		&::-webkit-scrollbar {
+			width: 4px;
+		}
+
+		&::-webkit-scrollbar-thumb {
+			background: rgba(255, 255, 255, 0.28);
+			border-radius: 999px;
+		}
+
+		&::before {
+			content: '';
+			display: block;
+			height: 3px;
+			background: var(--picker-accent, #FFD88A);
+			border-radius: 12px 12px 0 0;
+		}
 
 		.brand_picker_item {
-			padding: 10px 14px;
+			padding: 11px 16px;
 			font-size: 13px;
-			color: #fff;
+			font-weight: 500;
+			color: inherit;
 			cursor: pointer;
 			white-space: nowrap;
+			border-bottom: 1px solid var(--picker-divider, rgba(255, 255, 255, 0.12));
+			transition: background 0.15s;
 
-			&:hover,
+			&:last-child {
+				border-bottom: none;
+			}
+
+			&:hover {
+				background: var(--picker-hover-bg, rgba(255, 255, 255, 0.14));
+			}
+
 			&.active {
-				background: rgba(255, 255, 255, 0.12);
+				background: var(--picker-active-bg, rgba(255, 216, 138, 0.28));
+				font-weight: 600;
+				position: relative;
+				padding-left: 22px;
+
+				&::before {
+					content: '';
+					position: absolute;
+					left: 10px;
+					top: 50%;
+					transform: translateY(-50%);
+					width: 4px;
+					height: 4px;
+					border-radius: 50%;
+					background: var(--picker-accent, #FFD88A);
+				}
 			}
 		}
 	}
@@ -2431,6 +2624,14 @@
 		gap: 10px;
 		border-radius: 24px;
 		padding: 10px 16px;
+		border: 1px solid rgba(74, 55, 40, 0.1);
+		box-shadow: 0 2px 12px rgba(74, 55, 40, 0.08);
+		transition: box-shadow 0.2s, border-color 0.2s;
+
+		&:focus-within {
+			border-color: var(--suggest-theme, rgba(74, 55, 40, 0.22));
+			box-shadow: 0 4px 16px var(--suggest-theme-soft, rgba(74, 55, 40, 0.1));
+		}
 
 		.search_icon {
 			width: 14px;
@@ -2441,6 +2642,13 @@
 			filter: $search-icon-filter;
 		}
 
+		.search_divider {
+			width: 1px;
+			height: 16px;
+			background: rgba(74, 55, 40, 0.12);
+			flex-shrink: 0;
+		}
+
 		input {
 			flex: 1;
 			font-size: 14px;
@@ -2449,52 +2657,172 @@
 		}
 	}
 
-	.model_suggest_empty {
+	.expand_search_placeholder {
+		color: rgba(74, 55, 40, 0.38);
+		font-size: 14px;
+	}
+
+	.model_suggest_panel {
 		position: absolute;
-		top: calc(100% + 4px);
+		top: calc(100% + 6px);
 		left: 0;
 		right: 0;
-		margin-top: 0;
-		padding: 10px 14px;
-		font-size: 13px;
-		color: #999;
-		text-align: center;
+		padding: 8px;
+		border-radius: 16px;
 		background: #fff;
-		border-radius: 8px;
-		box-shadow: 0 8px 20px rgba(74, 55, 40, 0.16);
 		border: 1px solid rgba(74, 55, 40, 0.08);
+		box-shadow:
+			0 10px 28px rgba(61, 46, 34, 0.14),
+			0 2px 8px rgba(61, 46, 34, 0.06);
 		z-index: 20;
 	}
 
 	.model_suggest_list {
-		position: absolute;
-		top: calc(100% + 4px);
-		left: 0;
-		right: 0;
-		margin-top: 0;
-		max-height: 160px;
+		max-height: 204px;
 		overflow-y: auto;
-		border-radius: 8px;
-		background: #fff;
-		box-shadow: 0 8px 20px rgba(74, 55, 40, 0.16);
-		border: 1px solid rgba(74, 55, 40, 0.08);
-		z-index: 20;
+		display: flex;
+		flex-direction: column;
+		gap: 6px;
+		padding: 2px;
+
+		&::-webkit-scrollbar {
+			width: 4px;
+		}
+
+		&::-webkit-scrollbar-thumb {
+			background: rgba(74, 55, 40, 0.18);
+			border-radius: 999px;
+		}
 	}
 
 	.model_suggest_item {
-		padding: 10px 14px;
-		font-size: 13px;
-		color: $brown;
+		display: flex;
+		align-items: center;
+		gap: 10px;
+		padding: 8px 10px;
+		border-radius: 12px;
+		background: $panel-bg;
+		border: 1px solid rgba(74, 55, 40, 0.05);
 		cursor: pointer;
-		border-bottom: 1px solid rgba(74, 55, 40, 0.06);
-
-		&:last-child {
-			border-bottom: none;
-		}
+		transition: background 0.15s, border-color 0.15s, box-shadow 0.15s, transform 0.15s;
 
 		&:hover {
-			background: rgba(255, 255, 255, 0.6);
+			background: #fff;
+			border-color: var(--suggest-accent, rgba(255, 216, 138, 0.85));
+			box-shadow: 0 3px 10px var(--suggest-accent-soft, rgba(255, 216, 138, 0.28));
+			transform: translateY(-1px);
 		}
+
+		&:active {
+			transform: translateY(0);
+		}
+	}
+
+	.model_suggest_thumb {
+		width: 38px;
+		height: 38px;
+		flex-shrink: 0;
+		border-radius: 10px;
+		background: #fff;
+		border: 1px solid rgba(74, 55, 40, 0.06);
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		overflow: hidden;
+
+		image {
+			width: 34px;
+			height: 34px;
+		}
+	}
+
+	.model_suggest_thumb_ph {
+		width: 18px;
+		height: 18px;
+		border-radius: 4px;
+		background: rgba(74, 55, 40, 0.08);
+	}
+
+	.model_suggest_body {
+		flex: 1;
+		min-width: 0;
+		display: flex;
+		flex-direction: column;
+		gap: 3px;
+	}
+
+	.model_suggest_name {
+		font-size: 13px;
+		font-weight: 600;
+		color: $brown;
+		line-height: 1.3;
+		overflow: hidden;
+		text-overflow: ellipsis;
+		white-space: nowrap;
+	}
+
+	.model_suggest_brand {
+		font-size: 11px;
+		color: rgba(74, 55, 40, 0.42);
+		line-height: 1.2;
+		overflow: hidden;
+		text-overflow: ellipsis;
+		white-space: nowrap;
+	}
+
+	.model_suggest_meta {
+		flex-shrink: 0;
+		display: flex;
+		flex-direction: column;
+		align-items: flex-end;
+		gap: 2px;
+		min-width: 64px;
+	}
+
+	.model_suggest_price {
+		font-size: 13px;
+		font-weight: 700;
+		color: $orange;
+		line-height: 1.2;
+	}
+
+	.model_suggest_zd {
+		font-size: 10px;
+		color: rgba(74, 55, 40, 0.4);
+		line-height: 1.2;
+		white-space: nowrap;
+	}
+
+	.model_suggest_footer {
+		margin-top: 6px;
+		padding-top: 6px;
+		border-top: 1px solid rgba(74, 55, 40, 0.06);
+		text-align: center;
+
+		text {
+			font-size: 11px;
+			color: rgba(74, 55, 40, 0.38);
+		}
+	}
+
+	.model_suggest_empty {
+		position: absolute;
+		top: calc(100% + 6px);
+		left: 0;
+		right: 0;
+		padding: 16px 14px;
+		text-align: center;
+		background: #fff;
+		border-radius: 14px;
+		box-shadow: 0 8px 20px rgba(61, 46, 34, 0.1);
+		border: 1px dashed rgba(74, 55, 40, 0.12);
+		z-index: 20;
+	}
+
+	.model_suggest_empty_text {
+		font-size: 12px;
+		color: rgba(74, 55, 40, 0.45);
+		line-height: 1.5;
 	}
 
 	.col {
@@ -2636,6 +2964,41 @@
 			justify-content: center;
 		}
 	}
+
+	.product_list_footer {
+		padding: 16px 12px 8px;
+	}
+
+	.product_load_hint {
+		display: flex;
+		align-items: center;
+		justify-content: center;
+		gap: 8px;
+		padding: 10px 12px;
+		border-radius: 10px;
+		background: rgba(255, 255, 255, 0.72);
+		border: 1px solid rgba(74, 55, 40, 0.08);
+
+		text {
+			font-size: 12px;
+			color: rgba(74, 55, 40, 0.55);
+			line-height: 1.4;
+		}
+
+		&--done text {
+			color: rgba(74, 55, 40, 0.42);
+		}
+	}
+
+	.product_load_spinner {
+		width: 14px;
+		height: 14px;
+		border: 2px solid rgba(74, 55, 40, 0.15);
+		border-top-color: $brown;
+		border-radius: 50%;
+		animation: spin 0.8s linear infinite;
+		flex-shrink: 0;
+	}
 }
 
 .pk_page {

--
Gitblit v1.9.3