Sfoglia il codice sorgente

feat: 实现搜索功能和到货提醒对接真实接口

- 搜索页面接入热门搜索和历史记录接口
- 搜索结果页对接搜索接口并支持关键词高亮显示
- 到货提醒页面对接列表和取消接口,移除模拟数据
- 商品选择弹窗对接商品详情和加入购物车接口,支持库存判断
- 新增搜索相关API方法并更新项目开发规范文档
ylong 4 giorni fa
parent
commit
18cd2be15a

+ 59 - 0
.trae/rules/trae-project.md

@@ -0,0 +1,59 @@
+---
+alwaysApply: true
+---
+# Trae AI Coding Rules for Book-Hi
+
+## 1. Project Context & Technology Stack
+- **Framework**: uni-app + Vue 2
+- **UI Library**: uView UI v1 (Prefix: `u-`, no import needed for `easycom` components)
+- **CSS**: SCSS with `scoped`, use `rpx` for responsiveness.
+- **State Management**: Vuex (`store/`)
+- **Environment**: `.env.js` manages `apiUrl`.
+
+## 2. Architecture & Directory Structure
+- **Main Package**: `pages/` (Tabbar pages only: home, mine, sell, cart).
+- **Subpackages**:
+  - `pages-sell`: Mall/Selling features.
+  - `pages-car`: Shopping cart & Order flow.
+  - `pages-mine`: User center sub-pages.
+  - `pages-home`: Home sub-pages.
+- **Static Assets**:
+  - Global: `static/`
+  - Subpackage-specific: `pages-xxx/static/`
+
+## 3. Development Guidelines
+
+### 3.1 API Integration (Strict)
+- **Configuration**: `api/config.js` (Interceptor handles token & errors).
+- **Definition**:
+  - **Location**: `api/modules/*.js` (e.g., `mall.js`, `user.js`).
+  - **Naming**: Suffix with `Ajax` (e.g., `getGoodsListAjax`).
+  - **Format**: `(params) => uni.$u.http.post('/path', params)`
+- **Usage**:
+  - **Standard**: `this.$u.api.methodName(params).then(res => ...)`
+  - **Direct**: `uni.$u.http.post('/path', params).then(res => ...)` (Allowed for simple/temp requests)
+- **Response Handling**:
+  - Success: `res.code == 200`
+  - Error: Handled globally by interceptor (Toast), `401` triggers silent login.
+
+### 3.2 Component Development
+- **Global**: `components/` (Register in `main.js` if generic).
+- **Local/Business**: `pages-xxx/components/` (Import locally).
+- **uView Usage**: Use `u-` components directly (e.g., `<u-button>`, `<u-cell-item>`).
+
+### 3.3 Routing
+- **Jump**: `uni.navigateTo` for subpages, `uni.switchTab` for tabbar.
+- **Path**: ALWAYS use absolute paths (e.g., `/pages-sell/pages/detail`).
+
+### 3.4 Styling
+- **Scoped**: `<style lang="scss" scoped>`
+- **Units**: `rpx`
+- **Colors**: Use variables from `theme.scss` if available, or project standard colors (Primary: `#38C148` or similar based on `pages.json`).
+
+## 4. Code Generation Instructions
+- **When creating pages**: Check `pages.json` subpackage structure first.
+- **When adding features**:
+  1. Define API in `api/modules/`.
+  2. Create/Update Component or Page.
+  3. Ensure styles are scoped and responsive.
+- **Refactoring**: Prefer uView components over native HTML tags for consistency.

+ 56 - 0
TRAE_RULES.md

@@ -0,0 +1,56 @@
+# Trae AI Coding Rules for Book-Hi
+
+## 1. Project Context & Technology Stack
+- **Framework**: uni-app + Vue 2
+- **UI Library**: uView UI v1 (Prefix: `u-`, no import needed for `easycom` components)
+- **CSS**: SCSS with `scoped`, use `rpx` for responsiveness.
+- **State Management**: Vuex (`store/`)
+- **Environment**: `.env.js` manages `apiUrl`.
+
+## 2. Architecture & Directory Structure
+- **Main Package**: `pages/` (Tabbar pages only: home, mine, sell, cart).
+- **Subpackages**:
+  - `pages-sell`: Mall/Selling features.
+  - `pages-car`: Shopping cart & Order flow.
+  - `pages-mine`: User center sub-pages.
+  - `pages-home`: Home sub-pages.
+- **Static Assets**:
+  - Global: `static/`
+  - Subpackage-specific: `pages-xxx/static/`
+
+## 3. Development Guidelines
+
+### 3.1 API Integration (Strict)
+- **Configuration**: `api/config.js` (Interceptor handles token & errors).
+- **Definition**:
+  - **Location**: `api/modules/*.js` (e.g., `mall.js`, `user.js`).
+  - **Naming**: Suffix with `Ajax` (e.g., `getGoodsListAjax`).
+  - **Format**: `(params) => uni.$u.http.post('/path', params)`
+- **Usage**:
+  - **Standard**: `this.$u.api.methodName(params).then(res => ...)`
+  - **Direct**: `uni.$u.http.post('/path', params).then(res => ...)` (Allowed for simple/temp requests)
+- **Response Handling**:
+  - Success: `res.code == 200`
+  - Error: Handled globally by interceptor (Toast), `401` triggers silent login.
+
+### 3.2 Component Development
+- **Global**: `components/` (Register in `main.js` if generic).
+- **Local/Business**: `pages-xxx/components/` (Import locally).
+- **uView Usage**: Use `u-` components directly (e.g., `<u-button>`, `<u-cell-item>`).
+
+### 3.3 Routing
+- **Jump**: `uni.navigateTo` for subpages, `uni.switchTab` for tabbar.
+- **Path**: ALWAYS use absolute paths (e.g., `/pages-sell/pages/detail`).
+
+### 3.4 Styling
+- **Scoped**: `<style lang="scss" scoped>`
+- **Units**: `rpx`
+- **Colors**: Use variables from `theme.scss` if available, or project standard colors (Primary: `#38C148` or similar based on `pages.json`).
+
+## 4. Code Generation Instructions
+- **When creating pages**: Check `pages.json` subpackage structure first.
+- **When adding features**:
+  1. Define API in `api/modules/`.
+  2. Create/Update Component or Page.
+  3. Ensure styles are scoped and responsive.
+- **Refactoring**: Prefer uView components over native HTML tags for consistency.

+ 9 - 0
api/modules/mall.js

@@ -43,6 +43,9 @@ export const useMallApi = (Vue, vm) => {
 		
 		// 加入购物车
 		addCartAjax: (json) => vm.$u.post('/client/shop_cart/addCart',json),
+
+		// 新版加入购物车
+		addShopCartAjax: (json) => vm.$u.post('/api/token/shop/cart/add',json),
 		
 		// 购物车列表
 		getCartListAjax: (page) => vm.$u.post('/client/shop_cart/getCartList',{page:page}),
@@ -151,7 +154,13 @@ export const useMallApi = (Vue, vm) => {
 		 **/
 		getRefundOrderDetailAjax: (id) => vm.$u.post('/client/shopOrder/getRefundOrderDetail',{id:id}),
 		
+		// 热门搜索列表
+		getHotSearchListAjax: () => vm.$u.get('/token/shop/user/hotSearchList'),
 		
+		// 用户搜索历史
+		getSearchHistoryAjax: () => vm.$u.get('/token/shop/user/searchList'),
 		
+		// 用户搜索 (结果列表)
+		getSearchKeywordAjax: (params) => vm.$u.get('/token/shop/user/searchKeyword', params),
 	}
 }

+ 2 - 2
pages-car/components/arrival-reminder-item.vue

@@ -1,8 +1,8 @@
 <template>
     <view class="arrival-reminder-item">
-        <image class="book-cover" :src="info.cover || defaultCover" mode="aspectFill" />
+        <image class="book-cover" :src="info.cover" mode="aspectFill" />
         <view class="info-box">
-            <view class="book-title">{{ info.title || info.bookName }}</view>
+            <view class="book-title">{{ info.name }}</view>
             <view class="action-box">
                 <view class="btn-cancel" @click="onCancel">取消到货提醒</view>
             </view>

+ 15 - 4
pages-car/pages/arrival-reminder.vue

@@ -4,6 +4,8 @@
             ref="pageScroll"
             emptyText="暂无到货提醒"
             @updateList="updateList"
+            url="/token/shop/user/noticeArrivalList"
+            :immediate="true"
         >
             <view class="list-container">
                 <arrival-reminder-item 
@@ -33,7 +35,6 @@ export default {
     },
     methods: {
         updateList(data) {
-            // Mock data for display purposes
             this.list = data
         },
         handleCancel(item) {
@@ -42,8 +43,18 @@ export default {
                 content: '确定要取消该书籍的到货提醒吗?',
                 success: (res) => {
                     if (res.confirm) {
-                        this.list = this.list.filter(i => i.id !== item.id);
-                        uni.showToast({ title: '已取消', icon: 'none' });
+                        // 调用取消到货提醒接口
+                        uni.$u.http.post('/token/shop/user/noticeArrivalCancel', {
+                            isbn: item.isbn,
+                        }).then(res => {
+                            if (res.code === 200) {
+                                uni.showToast({ title: '已取消到货提醒', icon: 'none' });
+                                this.list = this.list.filter(row => row.isbn !== item.isbn);
+                                this.$refs.pageScroll?.loadData(true)
+                            } else {
+                                uni.showToast({ title: '取消到货提醒失败', icon: 'none' });
+                            }
+                        });
                     }
                 }
             });
@@ -62,4 +73,4 @@ export default {
     padding-top: 20rpx;
     padding-bottom: 20rpx;
 }
-</style>
+</style>

+ 20 - 7
pages-sell/components/recommend-item/index.vue

@@ -7,16 +7,16 @@
 			<view class="info-right">
 				<view class="title-author">
 					<view class="title-row">
-						<text class="title">{{ item.title }}</text>
+						<rich-text class="title" :nodes="highlightedName"></rich-text>
 					</view>
-					<text class="author">{{ item.author }}</text>
+					<rich-text class="author" :nodes="highlightedAuthor"></rich-text>
 				</view>
 
 				<view class="price-action">
 					<view class="price-box">
 						<text class="currency">¥</text>
-						<text class="price">{{ item.price }}</text>
-						<text class="original">¥{{ item.originalPrice }}</text>
+						<text class="price">{{ item.productPrice || item.price }}</text>
+						<text class="original">¥{{ item.price }}</text>
 					</view>
 
 					<view class="cart-btn" @click.stop="handleAddToCart">
@@ -32,7 +32,7 @@
 				<text class="label">简介</text>
 				<view class="indicator"></view>
 			</view>
-			<text class="desc-content">{{ item.desc || '暂无简介' }}</text>
+			<rich-text class="desc-content" :nodes="highlightedDesc"></rich-text>
 		</view>
 
 		<!-- Product Selection Popup -->
@@ -58,7 +58,22 @@ export default {
 			default: true
 		}
 	},
+	computed: {
+		highlightedName() {
+			return this.parseEmTag(this.item.name || this.item.title || '');
+		},
+		highlightedAuthor() {
+			return this.parseEmTag(this.item.author || '');
+		},
+		highlightedDesc() {
+			return this.parseEmTag(this.item.description || this.item.desc || '暂无简介');
+		}
+	},
 	methods: {
+		parseEmTag(text) {
+			if (!text) return '';
+			return text.replace(/<em>/g, '<span style="color: #38C148">').replace(/<\/em>/g, '</span>');
+		},
 		handleAddToCart() {
 			// Open the popup using ref
 			this.$refs.popup.open(this.item);
@@ -84,10 +99,8 @@ export default {
 			width: 172rpx;
 			height: 220rpx;
 			border-radius: 8rpx;
-			background-color: #f5f5f5;
 			margin-right: 24rpx;
 			flex-shrink: 0;
-			box-shadow: 0 4rpx 8rpx rgba(0, 0, 0, 0.1);
 		}
 
 		.info-right {

+ 336 - 249
pages-sell/components/select-good-popup/index.vue

@@ -14,9 +14,9 @@
 				<view class="info-right">
 					<view class="price-row">
 						<text class="currency">¥</text>
-						<text class="price">{{ currentProduct.price }}</text>
+						<text class="price">{{ displayUnitPrice }}</text>
 						<view class="drop-tag">
-							<text>↓可降至 ¥{{ currentProduct.minPrice || '8.67' }}</text>
+							<text>↓可降至 ¥{{ displayMinPrice }}</text>
 						</view>
 					</view>
 					<view class="tag-row">
@@ -41,17 +41,17 @@
 			<!-- Options -->
 			<view class="options-list">
 				<view class="option-item" v-for="(opt, index) in qualityOptions" :key="index"
-					:class="{ active: currentQuality === opt.value }" @click="selectQuality(opt.value)">
-					<image v-if="currentQuality === opt.value" src="/pages-sell/static/select-good/selected.png"
+					:class="{ active: currentQuality === opt.conditionType }" @click="selectQuality(opt)">
+					<image v-if="currentQuality === opt.conditionType" src="/pages-sell/static/select-good/selected.png"
 						class="bg-image"></image>
 					<view class="left">
-						<text class="opt-name">{{ opt.name }}</text>
-						<view class="opt-discount" :class="{ active: currentQuality === opt.value }">
+						<text class="opt-name">{{ qualityNames[index - 1] || '未知' }}</text>
+						<view class="opt-discount" :class="{ active: currentQuality === opt.conditionType }">
 							<text>{{ opt.discount }}折</text>
 						</view>
 					</view>
 					<view class="right">
-						<text>¥{{ opt.price }} ( 余额价 ¥{{ opt.balancePrice }} )</text>
+						<text>¥{{ opt.price }} ( 余额价 ¥{{ opt.balanceMoney }} )</text>
 					</view>
 				</view>
 			</view>
@@ -68,9 +68,9 @@
 					<text class="price">¥0.3</text>
 					<text class="desc">分享一人可降 0.5 元</text>
 				</view>
-				<view class="btn btn-green" @click="handleConfirm">
-					<text class="price">¥0.5</text>
-					<text class="desc">加入购物车</text>
+				<view class="btn btn-green" @click="handleAction">
+					<text v-if="hasStock" class="price">¥{{ displayTotalPrice }}</text>
+					<text class="desc" :class="{ 'notice': !hasStock }">{{ hasStock ? '加入购物车' : '到货通知' }}</text>
 				</view>
 			</view>
 		</view>
@@ -78,299 +78,386 @@
 </template>
 
 <script>
-export default {
-	name: 'SelectGoodPopup',
-	data() {
-		return {
-			visible: false,
-			quantity: 1,
-			currentQuality: 'medium',
-			currentProduct: {},
-			qualityOptions: [
-				{ name: '中等', value: 'medium', discount: '5.3', price: '33.3', balancePrice: '8.6' },
-				{ name: '良品', value: 'good', discount: '5.3', price: '33.3', balancePrice: '8.6' },
-				{ name: '良品', value: 'good2', discount: '5.3', price: '33.3', balancePrice: '8.6' }
-			]
-		};
-	},
-	computed: {
-		currentQualityName() {
-			const opt = this.qualityOptions.find(o => o.value === this.currentQuality);
-			return opt ? opt.name : '';
-		}
-	},
-	methods: {
-		open(product) {
-			this.currentProduct = product || {};
-			this.visible = true;
-			this.quantity = 1;
-			this.currentQuality = 'medium';
-		},
-		close() {
-			this.visible = false;
+	export default {
+		name: 'SelectGoodPopup',
+		data() {
+			return {
+				visible: false,
+				quantity: 1,
+				currentQuality: 1,
+				currentProduct: {},
+				qualityOptions: [],
+				//1-良好 2-中等 3-次品 4-全新
+				qualityNames: ['良好', '中等', '次品', '全新'],
+			};
 		},
-		selectQuality(val) {
-			this.currentQuality = val;
+		computed: {
+			currentQualityName() {
+				const opt = this.qualityNames[this.currentQuality - 1];
+				return opt || '未知';
+			},
+			selectedOption() {
+				return this.qualityOptions.find(o => o.conditionType === this.currentQuality) || {};
+			},
+			displayUnitPrice() {
+				return this.formatPrice(this.selectedOption.price);
+			},
+			displayMinPrice() {
+				return this.formatPrice(this.selectedOption.balanceMoney);
+			},
+			displayTotalPrice() {
+				const total = this.toNumber(this.selectedOption.price) * this.quantity;
+				return this.formatPrice(total);
+			},
+			hasStock() {
+				const stock = this.selectedOption.stockNum;
+				if (stock === 0) return false;
+				if (stock === undefined || stock === null || stock === '') return true;
+				return this.toNumber(stock) > 0;
+			}
 		},
-		handleConfirm() {
-			this.$emit('confirm', {
-				product: this.currentProduct,
-				quality: this.currentQuality,
-				quantity: this.quantity
-			});
-			this.close();
+		methods: {
+			open(product) {
+				this.visible = true;
+				this.quantity = 1;
+				if (product.isbn) {
+					this.getGoodQualityInfo(product.isbn);
+				}
+			},
+			//根据 isbn 获取商品品相信息
+			getGoodQualityInfo(isbn) {
+				uni.$u.http.get('/token/shop/bookDetail', { isbn }).then(res => {
+					console.log(res);
+					if (res.code === 200) {
+						this.currentProduct = res.data || {};
+						this.qualityOptions = res.data.skuList || [];
+						if (this.qualityOptions.length > 0) {
+							this.currentQuality = this.qualityOptions[0].conditionType
+						}
+					}
+				});
+			},
+
+			close() {
+				this.visible = false;
+			},
+			selectQuality(opt) {
+				this.currentQuality = opt.conditionType;
+			},
+			handleAction() {
+				if (!this.hasStock) {
+					this.handleNotify();
+					return;
+				}
+				this.handleConfirm();
+			},
+			handleNotify() {
+				//设置到货通知
+				uni.$u.http.post('/token/shop/user/noticeArrival', {
+					isbn: this.currentProduct.isbn,
+				}).then(res => {
+					if (res.code === 200) {
+						this.$u.toast('到货通知设置成功');
+					}
+				}).finally(() => {
+					this.close();
+				});
+			},
+			handleConfirm() {
+				if (!this.currentProduct.isbn) {
+					this.$u.toast('商品信息缺失');
+					return;
+				}
+
+				const selectedOption = this.selectedOption;
+				const conditionType = selectedOption.conditionType || this.currentQuality;
+
+				if (!conditionType) {
+					this.$u.toast('请选择品相');
+					return;
+				}
+
+				this.$u.api.addShopCartAjax({
+					isbn: this.currentProduct.isbn,
+					quantity: this.quantity,
+					conditionType: conditionType
+				}).then(res => {
+					if (res.code === 200) {
+						this.$u.toast('加入购物车成功');
+						this.$emit('confirm', {
+							product: this.currentProduct,
+							quality: this.currentQuality,
+							quantity: this.quantity
+						});
+						this.close();
+					}
+				});
+			},
+			toNumber(value) {
+				const num = Number(value);
+				return Number.isFinite(num) ? num : 0;
+			},
+			formatPrice(value) {
+				const num = this.toNumber(value);
+				return num.toFixed(2);
+			}
 		}
-	}
-};
+	};
 </script>
 
 <style lang="scss" scoped>
-.popup-content {
-	padding: 30rpx 30rpx 20rpx;
-	background-color: #fff;
-	position: relative;
-}
-
-.header {
-	display: flex;
-	justify-content: center;
-	align-items: center;
-	position: relative;
-	margin-bottom: 30rpx;
-	padding-bottom: 30rpx;
-	border-bottom: 2rpx dashed #eee;
-
-	.title {
-		font-size: 34rpx;
-		font-weight: bold;
-		color: #333;
+	.popup-content {
+		padding: 30rpx 30rpx 20rpx;
+		background-color: #fff;
+		position: relative;
 	}
 
-	.close-icon {
-		position: absolute;
-		right: 0;
-		top: 0;
-		width: 24rpx;
-		height: 24rpx;
-		padding: 10rpx;
-		box-sizing: content-box;
-	}
-}
-
-.product-info {
-	display: flex;
-	margin-bottom: 30rpx;
-
-	.book-cover {
-		width: 140rpx;
-		height: 180rpx;
-		border-radius: 8rpx;
-		margin-right: 24rpx;
-		background-color: #f5f5f5;
+	.header {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		position: relative;
+		margin-bottom: 30rpx;
+		padding-bottom: 30rpx;
+		border-bottom: 2rpx dashed #eee;
+
+		.title {
+			font-size: 34rpx;
+			font-weight: bold;
+			color: #333;
+		}
+
+		.close-icon {
+			position: absolute;
+			right: 0;
+			top: 0;
+			width: 24rpx;
+			height: 24rpx;
+			padding: 10rpx;
+			box-sizing: content-box;
+		}
 	}
 
-	.info-right {
-		flex: 1;
+	.product-info {
 		display: flex;
-		flex-direction: column;
-		justify-content: space-between;
-		padding: 10rpx 0;
+		margin-bottom: 30rpx;
+
+		.book-cover {
+			width: 140rpx;
+			height: 180rpx;
+			border-radius: 8rpx;
+			margin-right: 24rpx;
+			background-color: #f5f5f5;
+		}
 
-		.price-row {
+		.info-right {
+			flex: 1;
 			display: flex;
-			align-items: center;
-
-			.currency {
-				font-size: 36rpx;
-				color: #D81A00;
-				font-weight: bold;
-			}
+			flex-direction: column;
+			justify-content: space-between;
+			padding: 10rpx 0;
+
+			.price-row {
+				display: flex;
+				align-items: center;
+
+				.currency {
+					font-size: 36rpx;
+					color: #D81A00;
+					font-weight: bold;
+				}
 
-			.price {
-				font-size: 40rpx;
-				color: #D81A00;
-				font-weight: bold;
-				margin-right: 20rpx;
-				line-height: 1;
-			}
+				.price {
+					font-size: 40rpx;
+					color: #D81A00;
+					font-weight: bold;
+					margin-right: 20rpx;
+					line-height: 1;
+				}
 
-			.drop-tag {
-				background: #E8F9EA;
-				padding: 4rpx 12rpx;
-				border-radius: 4rpx;
+				.drop-tag {
+					background: #E8F9EA;
+					padding: 4rpx 12rpx;
+					border-radius: 4rpx;
 
-				text {
-					color: #38C248;
-					font-size: 24rpx;
-					font-weight: 500;
+					text {
+						color: #38C248;
+						font-size: 24rpx;
+						font-weight: 500;
+					}
 				}
 			}
-		}
 
-		.tag-row {
-			.quality-tag {
-				display: inline-block;
-				background: linear-gradient(0deg, #FFAB26 0%, #FFD426 100%);
-				border-radius: 21rpx 0px 21rpx 0px;
-				padding: 2rpx 24rpx;
-				margin-bottom: 24rpx;
-
-				text {
-					color: #fff;
-					font-size: 24rpx;
-					font-weight: 500;
+			.tag-row {
+				.quality-tag {
+					display: inline-block;
+					background: linear-gradient(0deg, #FFAB26 0%, #FFD426 100%);
+					border-radius: 21rpx 0px 21rpx 0px;
+					padding: 2rpx 24rpx;
+					margin-bottom: 24rpx;
+
+					text {
+						color: #fff;
+						font-size: 24rpx;
+						font-weight: 500;
+					}
 				}
 			}
 		}
 	}
-}
-
-.tips-row {
-	display: flex;
-	align-items: center;
-	margin-bottom: 16rpx;
-
-	text {
-		font-size: 26rpx;
-		color: #8D8D8D;
-		margin-right: 10rpx;
-	}
 
-	.tips-icon {
-		width: 36rpx;
-		height: 36rpx;
-	}
-}
+	.tips-row {
+		display: flex;
+		align-items: center;
+		margin-bottom: 16rpx;
 
-.promo-note {
-	margin-bottom: 40rpx;
+		text {
+			font-size: 26rpx;
+			color: #8D8D8D;
+			margin-right: 10rpx;
+		}
 
-	text {
-		font-size: 26rpx;
-		color: #8D8D8D;
+		.tips-icon {
+			width: 36rpx;
+			height: 36rpx;
+		}
 	}
-}
 
-.options-list {
-	margin-bottom: 40rpx;
+	.promo-note {
+		margin-bottom: 40rpx;
 
-	.option-item {
-		position: relative;
-		display: flex;
-		justify-content: space-between;
-		align-items: center;
-		background: #F8F8F8;
-		border-radius: 12rpx;
-		padding: 24rpx 30rpx;
-		margin-bottom: 24rpx;
-		border: 2rpx solid #dfdfdf;
-		transition: all 0.2s;
-
-		&.active {
-			border-color: transparent;
+		text {
+			font-size: 26rpx;
+			color: #8D8D8D;
 		}
+	}
 
-		.bg-image {
-			position: absolute;
-			top: -6rpx;
-			left: -1%;
-			width: 102%;
-			height: 110rpx;
-			z-index: 0;
-		}
+	.options-list {
+		margin-bottom: 40rpx;
 
-		.left,
-		.right {
+		.option-item {
 			position: relative;
-			z-index: 1;
-		}
-
-		.left {
 			display: flex;
+			justify-content: space-between;
 			align-items: center;
+			background: #F8F8F8;
+			border-radius: 12rpx;
+			padding: 24rpx 30rpx;
+			margin-bottom: 24rpx;
+			border: 2rpx solid #dfdfdf;
+			transition: all 0.2s;
+
+			&.active {
+				border-color: transparent;
+			}
 
-			.opt-name {
-				font-size: 30rpx;
-				font-weight: bold;
-				color: #333;
-				margin-right: 16rpx;
+			.bg-image {
+				position: absolute;
+				top: -6rpx;
+				left: -1%;
+				width: 102%;
+				height: 110rpx;
+				z-index: 0;
 			}
 
-			.opt-discount {
-				background: #D8D8D8;
-				padding: 0 20rpx;
-				border-radius: 0 20rpx 0 20rpx;
-				text {
-					color: #fff;
-					font-size: 24rpx;
-					display: inline-block;
+			.left,
+			.right {
+				position: relative;
+				z-index: 1;
+			}
+
+			.left {
+				display: flex;
+				align-items: center;
+
+				.opt-name {
+					font-size: 30rpx;
+					font-weight: bold;
+					color: #333;
+					margin-right: 16rpx;
 				}
 
-				&.active {
-					background: linear-gradient(0deg, #30E030 0%, #28C445 100%);
+				.opt-discount {
+					background: #D8D8D8;
+					padding: 0 20rpx;
+					border-radius: 0 20rpx 0 20rpx;
+
+					text {
+						color: #fff;
+						font-size: 24rpx;
+						display: inline-block;
+					}
+
+					&.active {
+						background: linear-gradient(0deg, #30E030 0%, #28C445 100%);
+					}
 				}
 			}
-		}
 
-		.right {
-			text {
-				font-size: 28rpx;
-				color: #333;
+			.right {
+				text {
+					font-size: 28rpx;
+					color: #333;
+				}
 			}
 		}
 	}
-}
-
-.quantity-row {
-	display: flex;
-	justify-content: space-between;
-	align-items: center;
-	margin-bottom: 50rpx;
-
-	.label {
-		font-size: 30rpx;
-		font-weight: bold;
-		color: #333;
-	}
-}
-
-.footer-btns {
-	display: flex;
-	justify-content: space-between;
-	padding-bottom: 10rpx;
 
-	.btn {
-		flex: 1;
-		height: 100rpx;
+	.quantity-row {
 		display: flex;
-		flex-direction: column;
+		justify-content: space-between;
 		align-items: center;
-		justify-content: center;
-		font-family: Source Han Sans SC;
-		font-weight: 500;
+		margin-bottom: 50rpx;
 
-		.price {
-			font-size: 38rpx;
-			color: #fff;
-			line-height: 1.2;
+		.label {
+			font-size: 30rpx;
+			font-weight: bold;
+			color: #333;
 		}
+	}
 
-		.desc {
-			font-size: 24rpx;
-			color: #fff;
-		}
+	.footer-btns {
+		display: flex;
+		justify-content: space-between;
+		padding-bottom: 10rpx;
 
-		&.btn-orange {
-			background: linear-gradient(0deg, #EFA941 0%, #FFB84F 100%);
-			width: 340rpx;
-			border-radius: 50rpx 0 0 50rpx;
-		}
+		.btn {
+			flex: 1;
+			height: 100rpx;
+			display: flex;
+			flex-direction: column;
+			align-items: center;
+			justify-content: center;
+			font-family: Source Han Sans SC;
+			font-weight: 500;
 
-		&.btn-green {
-			width: 340rpx;
-			background: linear-gradient(0deg, #38C248 0%, #5FEA6F 100%);
-			border-radius: 0 50rpx 50rpx 0;
+			.price {
+				font-size: 38rpx;
+				color: #fff;
+				line-height: 1.2;
+			}
+
+			.desc {
+				font-size: 24rpx;
+				color: #fff;
+			}
+
+			.notice {
+				font-size: 32rpx;
+				color: #fff;
+			}
+
+			&.btn-orange {
+				background: linear-gradient(0deg, #EFA941 0%, #FFB84F 100%);
+				width: 340rpx;
+				border-radius: 50rpx 0 0 50rpx;
+			}
+
+			&.btn-green {
+				width: 340rpx;
+				background: linear-gradient(0deg, #38C248 0%, #5FEA6F 100%);
+				border-radius: 0 50rpx 50rpx 0;
+			}
 		}
 	}
-}
 </style>

+ 454 - 442
pages-sell/components/sell-container/index.vue

@@ -145,7 +145,8 @@
 
 				<scroll-view scroll-x class="book-scroll" :show-scrollbar="false">
 					<view class="book-list">
-						<view class="book-item" v-for="(book, index) in recommendBooks" :key="index" @click="navigateTo('/pages-sell/pages/detail')">
+						<view class="book-item" v-for="(book, index) in recommendBooks" :key="index"
+							@click="navigateTo('/pages-sell/pages/detail')">
 							<image :src="book.cover" class="book-image" mode="aspectFill"></image>
 							<text class="book-name">{{ book.title }}</text>
 							<view class="price-row">
@@ -169,554 +170,565 @@
 </template>
 
 <script>
-export default {
-	name: 'SellContainer',
-	data() {
-		return {
-			barStyle: {
-				backgroundColor: 'transparent',
-				background: "url('/pages-sell/static/tab-selected.png') no-repeat center",
-				backgroundSize: '100% 100%',
-				position: 'relative',
-				top: '-6rpx',
-			},
-			swiperList: [
-				{
-					image: '/pages-sell/static/banner-3.png'
-				},
-				{
-					image: '/pages-sell/static/banner-1.png'
+	export default {
+		name: 'SellContainer',
+		data() {
+			return {
+				barStyle: {
+					backgroundColor: 'transparent',
+					background: "url('/pages-sell/static/tab-selected.png') no-repeat center",
+					backgroundSize: '100% 100%',
+					position: 'relative',
+					top: '-6rpx',
 				},
-				{
-					image: '/pages-sell/static/banner-2.png'
-				}
-			],
-			statusBarHeight: 20,
-			keyword: '',
-			// u-tabs 需要对象数组 [{name: 'xxx'}]
-			hotTagList: [
-				{ name: '热搜' },
-				{ name: '励志' },
-				{ name: '绘本' },
-				{ name: '诺贝尔文学奖' },
-				{ name: '茅盾奖' },
-				{ name: '童书' }
-			],
-			currentHotTag: 0,
-			// 临时的网络书封面图片
-			bookCoverUrl: 'https://img.yzcdn.cn/vant/cat.jpeg',
-			categoryList: [
-				{ name: '热销榜单', icon: '/pages-sell/static/icon-hot-sales.png' },
-				{ name: '心灵 / 成长', icon: '/pages-sell/static/icon-heart-growth.png' },
-				{ name: '诺贝尔文学奖', icon: '/pages-sell/static/icon-nobel.png' },
-				{ name: '茅盾文学奖', icon: '/pages-sell/static/icon-maodun.png' },
-				{ name: '樊登书单', icon: '/pages-sell/static/icon-fandeng.png' },
-				{ name: '东野圭吾', icon: '/pages-sell/static/icon-dongye.png' },
-				{ name: '余华', icon: '/pages-sell/static/icon-yuhua.png' },
-				{ name: '村上春树', icon: '/pages-sell/static/icon-haruki.png' },
-				{ name: '童书', icon: '/pages-sell/static/icon-children.png' },
-				{ name: '书嗨推荐', icon: '/pages-sell/static/icon-recommend.png' }
-			],
-			recommendBooks: [
-				{ title: '山河岁月', price: '6.80', original: '36.80', cover: 'https://img.yzcdn.cn/vant/cat.jpeg' },
-				{ title: '山河岁月', price: '6.80', original: '36.80', cover: 'https://img.yzcdn.cn/vant/cat.jpeg' },
-				{ title: '山河岁月', price: '6.80', original: '36.80', cover: 'https://img.yzcdn.cn/vant/cat.jpeg' }
-			]
-		}
-	},
-	created() {
-		const systemInfo = uni.getSystemInfoSync();
-		this.statusBarHeight = systemInfo.statusBarHeight || 20;
-	},
-	methods: {
-		handleCategory(item) {
-			console.log('点击分类:', item.name);
-		},
-		changeHotTag(index) {
-			this.currentHotTag = index;
-			console.log('切换标签:', index);
-		},
-		//跳转 URL
-		navigateTo(url) {
-			uni.navigateTo({
-				url: url
-			});
+				swiperList: [
+					{
+						image: '/pages-sell/static/banner-3.png'
+					},
+					{
+						image: '/pages-sell/static/banner-1.png'
+					},
+					{
+						image: '/pages-sell/static/banner-2.png'
+					}
+				],
+				statusBarHeight: 20,
+				keyword: '',
+				// u-tabs 需要对象数组 [{name: 'xxx'}]
+				hotTagList: [
+					{ name: '热搜' },
+					{ name: '励志' },
+					{ name: '绘本' },
+					{ name: '诺贝尔文学奖' },
+					{ name: '茅盾奖' },
+					{ name: '童书' }
+				],
+				currentHotTag: 0,
+				// 临时的网络书封面图片
+				bookCoverUrl: 'https://img.yzcdn.cn/vant/cat.jpeg',
+				categoryList: [
+					{ name: '热销榜单', icon: '/pages-sell/static/icon-hot-sales.png' },
+					{ name: '心灵 / 成长', icon: '/pages-sell/static/icon-heart-growth.png' },
+					{ name: '诺贝尔文学奖', icon: '/pages-sell/static/icon-nobel.png' },
+					{ name: '茅盾文学奖', icon: '/pages-sell/static/icon-maodun.png' },
+					{ name: '樊登书单', icon: '/pages-sell/static/icon-fandeng.png' },
+					{ name: '东野圭吾', icon: '/pages-sell/static/icon-dongye.png' },
+					{ name: '余华', icon: '/pages-sell/static/icon-yuhua.png' },
+					{ name: '村上春树', icon: '/pages-sell/static/icon-haruki.png' },
+					{ name: '童书', icon: '/pages-sell/static/icon-children.png' },
+					{ name: '书嗨推荐', icon: '/pages-sell/static/icon-recommend.png' }
+				],
+				recommendBooks: [
+					{ title: '山河岁月', price: '6.80', original: '36.80', cover: 'https://img.yzcdn.cn/vant/cat.jpeg' },
+					{ title: '山河岁月', price: '6.80', original: '36.80', cover: 'https://img.yzcdn.cn/vant/cat.jpeg' },
+					{ title: '山河岁月', price: '6.80', original: '36.80', cover: 'https://img.yzcdn.cn/vant/cat.jpeg' }
+				]
+			}
 		},
+		created() {
+			const systemInfo = uni.getSystemInfoSync();
+			this.statusBarHeight = systemInfo.statusBarHeight || 20;
 
-		goRecommend() {
-			uni.navigateTo({
-				url: '/pages-sell/pages/recommend'
-			});
+			this.getIndexCateInfo()
 		},
-		goHotSell() {
-			uni.navigateTo({
-				url: '/pages-sell/pages/hot-sell'
-			});
+		methods: {
+			handleCategory(item) {
+				console.log('点击分类:', item.name);
+			},
+			changeHotTag(index) {
+				this.currentHotTag = index;
+				console.log('切换标签:', index);
+			},
+			//跳转 URL
+			navigateTo(url) {
+				uni.navigateTo({
+					url: url
+				});
+			},
+
+			goRecommend() {
+				uni.navigateTo({
+					url: '/pages-sell/pages/recommend'
+				});
+			},
+			goHotSell() {
+				uni.navigateTo({
+					url: '/pages-sell/pages/hot-sell'
+				});
+			},
+			//获取首页装修信息
+			getIndexCateInfo() {
+				uni.$u.http.get('/token/shop/showIndex/getIndexCateInfo?position=diamond_area').then(res => {
+					console.log(res)
+					if (res.code == 200) {
+						console.log(res.data)
+					}
+				})
+			}
 		}
 	}
-}
 </script>
 
 <style lang="scss" scoped>
-.sell-container {
-	position: relative;
-	min-height: 100vh;
-	background-color: #F6F6F6;
-	overflow-x: hidden;
-}
-
-/* 顶部大背景图 */
-.top-bg-image {
-	position: absolute;
-	top: 0;
-	left: 0;
-	width: 100%;
-	z-index: 0;
-	display: block;
-}
-
-/* 导航栏 */
-.custom-navbar {
-	position: fixed;
-	top: 0;
-	left: 0;
-	width: 100%;
-	z-index: 100;
-	display: flex;
-	align-items: center;
-	justify-content: center;
-
-	.navbar-content {
-		height: 44px;
-		width: 100%;
-		display: flex;
-		align-items: center;
-		justify-content: center;
+	.sell-container {
 		position: relative;
-
-		.navbar-title {
-			color: #fff;
-			font-size: 36rpx;
-			font-weight: 600;
-		}
+		min-height: 100vh;
+		background-color: #F6F6F6;
+		overflow-x: hidden;
 	}
-}
 
-.main-content {
-	position: relative;
-	z-index: 1;
-	padding: 0 24rpx;
-}
-
-/* 搜索框 */
-.search-wrapper {
-	margin-top: 10rpx;
-	margin-bottom: 20rpx;
+	/* 顶部大背景图 */
+	.top-bg-image {
+		position: absolute;
+		top: 0;
+		left: 0;
+		width: 100%;
+		z-index: 0;
+		display: block;
+	}
 
-	.search-box-uview {
-		height: 80rpx;
-		background-color: #fff;
-		border-radius: 40rpx;
+	/* 导航栏 */
+	.custom-navbar {
+		position: fixed;
+		top: 0;
+		left: 0;
+		width: 100%;
+		z-index: 100;
 		display: flex;
 		align-items: center;
-		padding: 0 10rpx 0 16rpx;
-		position: relative;
-
-		/* 覆盖 u-search 的 padding 以适配 */
-		::v-deep .u-search {
-			flex: 1;
-			/* 让输入框不遮挡右侧按钮 */
-			padding-right: 140rpx !important;
-		}
+		justify-content: center;
 
-		.search-btn-overlay {
-			position: absolute;
-			right: 8rpx;
-			top: 50%;
-			transform: translateY(-50%);
-			width: 140rpx;
-			height: 64rpx;
-			background: linear-gradient(0deg, #37C148 0%, #6ADD83 100%);
-			border-radius: 32rpx;
+		.navbar-content {
+			height: 44px;
+			width: 100%;
 			display: flex;
 			align-items: center;
 			justify-content: center;
-			z-index: 2;
+			position: relative;
 
-			text {
+			.navbar-title {
 				color: #fff;
-				font-size: 28rpx;
-				font-weight: 500;
+				font-size: 36rpx;
+				font-weight: 600;
 			}
 		}
 	}
-}
-
-/* 顶部横幅 */
-.top-banner-wrapper {
-	width: 100%;
-	margin-bottom: 30rpx;
-	position: relative;
 
-	.top-banner-img {
-		width: 100%;
-		border-radius: 40rpx;
-		display: block;
+	.main-content {
+		position: relative;
+		z-index: 1;
+		padding: 0 24rpx;
 	}
-}
 
-/* 分类图标 */
-.category-grid {
-	display: flex;
-	flex-wrap: wrap;
-	margin-bottom: 10rpx;
+	/* 搜索框 */
+	.search-wrapper {
+		margin-top: 10rpx;
+		margin-bottom: 20rpx;
 
-	.grid-item {
-		width: 20%;
-		display: flex;
-		flex-direction: column;
-		align-items: center;
-		margin-bottom: 30rpx;
-
-		.icon-circle {
-			width: 96rpx;
-			height: 96rpx;
+		.search-box-uview {
+			height: 80rpx;
+			background-color: #fff;
+			border-radius: 40rpx;
 			display: flex;
 			align-items: center;
-			justify-content: center;
-			margin-bottom: 12rpx;
+			padding: 0 10rpx 0 16rpx;
+			position: relative;
 
-			.cat-icon {
-				width: 100%;
-				height: 100%;
+			/* 覆盖 u-search 的 padding 以适配 */
+			::v-deep .u-search {
+				flex: 1;
+				/* 让输入框不遮挡右侧按钮 */
+				padding-right: 140rpx !important;
 			}
-		}
 
-		.cat-name {
-			font-size: 24rpx;
-			color: #333;
-			font-weight: 500;
+			.search-btn-overlay {
+				position: absolute;
+				right: 8rpx;
+				top: 50%;
+				transform: translateY(-50%);
+				width: 140rpx;
+				height: 64rpx;
+				background: linear-gradient(0deg, #37C148 0%, #6ADD83 100%);
+				border-radius: 32rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				z-index: 2;
+
+				text {
+					color: #fff;
+					font-size: 28rpx;
+					font-weight: 500;
+				}
+			}
 		}
 	}
-}
 
-/* 推广双卡片 */
-.promo-dual-card {
-	display: flex;
-	justify-content: space-between;
-	margin-bottom: 24rpx;
-
-	.card-left {
-		width: 48%;
-		height: 252rpx;
-		border-radius: 20rpx;
+	/* 顶部横幅 */
+	.top-banner-wrapper {
+		width: 100%;
+		margin-bottom: 30rpx;
 		position: relative;
-		overflow: hidden;
+
+		.top-banner-img {
+			width: 100%;
+			border-radius: 40rpx;
+			display: block;
+		}
 	}
 
-	.card-right {
-		width: 48%;
-		height: 252rpx;
-		/* Updated background per request */
-		background: linear-gradient(to bottom, #FFD7C3 0%, #FFFFFF 32%);
-		border-radius: 20rpx;
-		padding: 20rpx;
-		box-sizing: border-box;
+	/* 分类图标 */
+	.category-grid {
+		display: flex;
+		flex-wrap: wrap;
+		margin-bottom: 10rpx;
 
-		.right-header {
+		.grid-item {
+			width: 20%;
 			display: flex;
+			flex-direction: column;
 			align-items: center;
-			justify-content: center;
-			margin-bottom: 20rpx;
-
-			.right-title {
-				font-size: 30rpx;
-				font-weight: bold;
-				color: #333;
-				margin: 0 10rpx;
-			}
+			margin-bottom: 30rpx;
 
-			.fire-icon {
-				width: 30rpx;
-				height: 30rpx;
-			}
+			.icon-circle {
+				width: 96rpx;
+				height: 96rpx;
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-bottom: 12rpx;
 
-			.flip {
-				transform: scaleX(-1);
+				.cat-icon {
+					width: 100%;
+					height: 100%;
+				}
 			}
-		}
 
-		.products-container {
-			display: flex;
-			justify-content: space-between;
-			gap: 20rpx;
-
-			.product-cover {
-				flex: 1;
-				height: 160rpx;
-				border-radius: 12rpx;
-				background-color: #f0f0f0;
+			.cat-name {
+				font-size: 24rpx;
+				color: #333;
+				font-weight: 500;
 			}
 		}
 	}
-}
-
-/* 信息双卡片 */
-.info-dual-card {
-	display: flex;
-	justify-content: space-between;
-	margin-bottom: 24rpx;
-
-	.info-card {
-		width: 48%;
-		padding: 24rpx;
-		border-radius: 12px;
-		/* Updated radius */
+
+	/* 推广双卡片 */
+	.promo-dual-card {
 		display: flex;
 		justify-content: space-between;
-		align-items: center;
-		height: 140rpx;
-		box-sizing: border-box;
-		position: relative;
-		/* For absolute icon */
-		overflow: hidden;
+		margin-bottom: 24rpx;
 
-		&.bg-orange {
-			background: #FFF3E0;
-			border: 1px solid #FFB72A;
+		.card-left {
+			width: 48%;
+			height: 252rpx;
+			border-radius: 20rpx;
+			position: relative;
+			overflow: hidden;
 		}
 
-		&.bg-green {
-			background: #D4F1D8;
-			border: 1px solid #54A94E;
-		}
+		.card-right {
+			width: 48%;
+			height: 252rpx;
+			/* Updated background per request */
+			background: linear-gradient(to bottom, #FFD7C3 0%, #FFFFFF 32%);
+			border-radius: 20rpx;
+			padding: 20rpx;
+			box-sizing: border-box;
 
-		.info-text-group {
-			flex: 1;
-			z-index: 1;
-			/* Ensure text is above */
+			.right-header {
+				display: flex;
+				align-items: center;
+				justify-content: center;
+				margin-bottom: 20rpx;
 
-			.info-title {
-				font-size: 28rpx;
-				font-weight: bold;
-				display: block;
-				margin-bottom: 6rpx;
-			}
+				.right-title {
+					font-size: 30rpx;
+					font-weight: bold;
+					color: #333;
+					margin: 0 10rpx;
+				}
+
+				.fire-icon {
+					width: 30rpx;
+					height: 30rpx;
+				}
 
-			.info-desc {
-				font-size: 22rpx;
-				line-height: 1.2;
+				.flip {
+					transform: scaleX(-1);
+				}
 			}
 
-			.text-orange {
-				color: #DB832D;
+			.products-container {
+				display: flex;
+				justify-content: space-between;
+				gap: 20rpx;
+
+				.product-cover {
+					flex: 1;
+					height: 160rpx;
+					border-radius: 12rpx;
+					background-color: #f0f0f0;
+				}
 			}
+		}
+	}
 
-			.text-orange-light {
-				color: #DB832D;
+	/* 信息双卡片 */
+	.info-dual-card {
+		display: flex;
+		justify-content: space-between;
+		margin-bottom: 24rpx;
+
+		.info-card {
+			width: 48%;
+			padding: 24rpx;
+			border-radius: 12px;
+			/* Updated radius */
+			display: flex;
+			justify-content: space-between;
+			align-items: center;
+			height: 140rpx;
+			box-sizing: border-box;
+			position: relative;
+			/* For absolute icon */
+			overflow: hidden;
+
+			&.bg-orange {
+				background: #FFF3E0;
+				border: 1px solid #FFB72A;
 			}
 
-			.text-green {
-				color: #1F8049;
+			&.bg-green {
+				background: #D4F1D8;
+				border: 1px solid #54A94E;
 			}
 
-			.text-green-light {
-				color: #1F8049;
+			.info-text-group {
+				flex: 1;
+				z-index: 1;
+				/* Ensure text is above */
+
+				.info-title {
+					font-size: 28rpx;
+					font-weight: bold;
+					display: block;
+					margin-bottom: 6rpx;
+				}
+
+				.info-desc {
+					font-size: 22rpx;
+					line-height: 1.2;
+				}
+
+				.text-orange {
+					color: #DB832D;
+				}
+
+				.text-orange-light {
+					color: #DB832D;
+				}
+
+				.text-green {
+					color: #1F8049;
+				}
+
+				.text-green-light {
+					color: #1F8049;
+				}
 			}
-		}
 
-		.info-icon {
-			width: 100rpx;
-			/* Slightly larger maybe */
-			height: 100rpx;
-			position: absolute;
-			right: 0;
-			bottom: 0;
-			z-index: 0;
-			opacity: 0.8;
+			.info-icon {
+				width: 100rpx;
+				/* Slightly larger maybe */
+				height: 100rpx;
+				position: absolute;
+				right: 0;
+				bottom: 0;
+				z-index: 0;
+				opacity: 0.8;
+			}
 		}
 	}
-}
 
-/* 公众号 */
-.gzh-section {
-	margin-bottom: 30rpx;
-	height: 180rpx;
-	/* Fixed height for consistency */
-	border-radius: 20rpx;
-	overflow: hidden;
-
-	.gzh-bg-wrapper {
-		width: 100%;
-		height: 100%;
-		position: relative;
+	/* 公众号 */
+	.gzh-section {
+		margin-bottom: 30rpx;
+		height: 180rpx;
+		/* Fixed height for consistency */
+		border-radius: 20rpx;
+		overflow: hidden;
 
-		.gzh-img-bg {
+		.gzh-bg-wrapper {
 			width: 100%;
 			height: 100%;
-			position: absolute;
-			top: 0;
-			left: 0;
-		}
+			position: relative;
 
-		.gzh-content-overlay {
-			position: absolute;
-			top: 0;
-			left: 0;
-			width: 60%;
-			/* Only cover left side */
-			height: 100%;
-			padding: 30rpx;
-			display: flex;
-			flex-direction: column;
-			justify-content: center;
-
-			.gzh-title {
-				font-size: 32rpx;
-				font-weight: bold;
-				color: #134E13;
-				/* Dark green */
-				margin-bottom: 16rpx;
+			.gzh-img-bg {
+				width: 100%;
+				height: 100%;
+				position: absolute;
+				top: 0;
+				left: 0;
 			}
 
-			.gzh-subtitle-pill {
-				background: #FFF;
-				border-radius: 24rpx;
-				padding: 0 14rpx;
-				line-height: 1.4;
-				align-self: flex-start;
+			.gzh-content-overlay {
+				position: absolute;
+				top: 0;
+				left: 0;
+				width: 60%;
+				/* Only cover left side */
+				height: 100%;
+				padding: 30rpx;
+				display: flex;
+				flex-direction: column;
+				justify-content: center;
 
-				.gzh-subtitle {
-					font-size: 22rpx;
+				.gzh-title {
+					font-size: 32rpx;
+					font-weight: bold;
 					color: #134E13;
-					font-weight: 500;
+					/* Dark green */
+					margin-bottom: 16rpx;
+				}
+
+				.gzh-subtitle-pill {
+					background: #FFF;
+					border-radius: 24rpx;
+					padding: 0 14rpx;
+					line-height: 1.4;
+					align-self: flex-start;
+
+					.gzh-subtitle {
+						font-size: 22rpx;
+						color: #134E13;
+						font-weight: 500;
+					}
 				}
 			}
 		}
 	}
-}
-
-/* 书嗨推荐 */
-.recommend-section {
-	background-color: #fff;
-	border-radius: 20rpx;
-	padding: 30rpx;
 
-	.section-header {
-		display: flex;
-		justify-content: space-between;
-		align-items: center;
-		margin-bottom: 24rpx;
-
-		.section-title {
-			font-size: 32rpx;
-			font-weight: bold;
-			color: #333;
-		}
+	/* 书嗨推荐 */
+	.recommend-section {
+		background-color: #fff;
+		border-radius: 20rpx;
+		padding: 30rpx;
 
-		.view-more {
+		.section-header {
 			display: flex;
+			justify-content: space-between;
 			align-items: center;
-			font-size: 24rpx;
-			color: #8D8D8D;
+			margin-bottom: 24rpx;
 
-			.arrow-icon {
-				width: 12rpx;
-				margin-left: 6rpx;
+			.section-title {
+				font-size: 32rpx;
+				font-weight: bold;
+				color: #333;
 			}
-		}
-	}
 
-	.book-scroll {
-		width: 100%;
-		white-space: nowrap;
+			.view-more {
+				display: flex;
+				align-items: center;
+				font-size: 24rpx;
+				color: #8D8D8D;
 
-		.book-list {
-			display: flex;
-			padding-bottom: 10rpx;
+				.arrow-icon {
+					width: 12rpx;
+					margin-left: 6rpx;
+				}
+			}
 		}
 
-		.book-item {
-			width: 200rpx;
-			margin-right: 24rpx;
-			display: flex;
-			flex-direction: column;
-
-			.book-image {
-				width: 200rpx;
-				height: 255rpx;
-				border-radius: 2rpx;
-				margin-bottom: 16rpx;
-				background-color: #f9f9f9;
-			}
+		.book-scroll {
+			width: 100%;
+			white-space: nowrap;
 
-			.book-name {
-				font-family: 'Source Han Sans SC';
-				font-weight: bold;
-				font-size: 28rpx;
-				color: #303030;
-				margin-bottom: 10rpx;
-				overflow: hidden;
-				text-overflow: ellipsis;
-				white-space: nowrap;
+			.book-list {
+				display: flex;
+				padding-bottom: 10rpx;
 			}
 
-			.price-row {
+			.book-item {
+				width: 200rpx;
+				margin-right: 24rpx;
 				display: flex;
-				align-items: baseline;
-				margin-bottom: 12rpx;
-
-				.currency {
-					font-family: 'Source Han Sans SC';
-					font-weight: 500;
-					font-size: 22rpx;
-					color: #D81A00;
+				flex-direction: column;
+
+				.book-image {
+					width: 200rpx;
+					height: 255rpx;
+					border-radius: 2rpx;
+					margin-bottom: 16rpx;
+					background-color: #f9f9f9;
 				}
 
-				.price-val {
+				.book-name {
 					font-family: 'Source Han Sans SC';
-					font-weight: 500;
+					font-weight: bold;
 					font-size: 28rpx;
-					color: #D81A00;
-					margin-right: 12rpx;
+					color: #303030;
+					margin-bottom: 10rpx;
+					overflow: hidden;
+					text-overflow: ellipsis;
+					white-space: nowrap;
 				}
 
-				.price-old {
-					font-family: 'Source Han Sans SC';
-					font-weight: 500;
-					font-size: 22rpx;
-					color: #999999;
-					text-decoration: line-through;
-				}
-			}
-
-			.add-btn {
-				width: fit-content;
-				height: 36rpx;
-				line-height: 36rpx;
-				background: linear-gradient(0deg, #4ED964 0%, #4ED964 100%);
-				border-radius: 18rpx;
-				padding: 0 20rpx;
-				display: flex;
-				align-items: center;
-				justify-content: center;
-
-				text {
-					font-size: 22rpx;
-					color: #fff;
+				.price-row {
+					display: flex;
+					align-items: baseline;
+					margin-bottom: 12rpx;
+
+					.currency {
+						font-family: 'Source Han Sans SC';
+						font-weight: 500;
+						font-size: 22rpx;
+						color: #D81A00;
+					}
+
+					.price-val {
+						font-family: 'Source Han Sans SC';
+						font-weight: 500;
+						font-size: 28rpx;
+						color: #D81A00;
+						margin-right: 12rpx;
+					}
+
+					.price-old {
+						font-family: 'Source Han Sans SC';
+						font-weight: 500;
+						font-size: 22rpx;
+						color: #999999;
+						text-decoration: line-through;
+					}
 				}
 
-				.cart-symbol {
-					width: 24rpx;
-					height: 24rpx;
-					margin-left: 6rpx;
+				.add-btn {
+					width: fit-content;
+					height: 36rpx;
+					line-height: 36rpx;
+					background: linear-gradient(0deg, #4ED964 0%, #4ED964 100%);
+					border-radius: 18rpx;
+					padding: 0 20rpx;
+					display: flex;
+					align-items: center;
+					justify-content: center;
+
+					text {
+						font-size: 22rpx;
+						color: #fff;
+					}
+
+					.cart-symbol {
+						width: 24rpx;
+						height: 24rpx;
+						margin-left: 6rpx;
+					}
 				}
 			}
 		}
 	}
-}
 
-.bottom-safe-area {
-	height: 30rpx
-}
+	.bottom-safe-area {
+		height: 30rpx
+	}
 </style>

+ 36 - 50
pages-sell/pages/search-result.vue

@@ -2,7 +2,7 @@
     <view class="search-result-page">
         <image class="top-bg-image" src="/pages-sell/static/top-bg.png" mode="widthFix"></image>
 
-        <Navbar title="书嗨" :titleSize="36" title-color="#ffffff" back-icon-color="#ffffff"></Navbar>
+        <Navbar title="书嗨" :titleSize="36" :title-color="navbarTitleColor" :back-icon-color="navbarIconColor" :background="navbarBackground"></Navbar>
 
         <!-- Custom Header -->
         <view class="search-bar-wrapper">
@@ -51,9 +51,6 @@
                 <RecommendItem v-for="(item, index) in bookList" :key="index" :item="item" @add-cart="addToCart" :show-desc="false">
                 </RecommendItem>
             </view>
-            
-            <!-- Service Popup -->
-            <ServicePopup ref="servicePopup"></ServicePopup>
         </view>
     </view>
 </template>
@@ -62,18 +59,18 @@
 import RecommendItem from '../components/recommend-item/index.vue';
 import HotRecommendItem from '../components/hot-recommend-item/index.vue';
 import Navbar from '@/components/navbar/navbar.vue';
-import ServicePopup from '../components/service-popup/index.vue';
 
 export default {
     components: {
         RecommendItem,
         HotRecommendItem,
         Navbar,
-        ServicePopup
     },
     data() {
         return {
-            keyword: '习近平新时代思想',
+            keyword: '',
+            pageNum: 1,
+            pageSize: 10,
             hotBook: {
                 id: 1,
                 title: '山河岁月',
@@ -82,53 +79,42 @@ export default {
                 discount: '5.3折',
                 discountDesc: '省9.8元'
             },
-            bookList: [
-                {
-                    id: 2,
-                    title: '山河岁月',
-                    author: '本书编写组',
-                    cover: '/static/img/1.png',
-                    price: '6.80',
-                    originalPrice: '36.80',
-                    desc: '“山河岁月”以宏大的历史视野,讲述了... '
-                },
-                {
-                    id: 3,
-                    title: '山河岁月',
-                    author: '本书编写组',
-                    cover: '/static/img/1.png',
-                    price: '6.80',
-                    originalPrice: '36.80',
-                    desc: '“山河岁月”以宏大的历史视野,讲述了... '
-                },
-                {
-                    id: 4,
-                    title: '山河岁月',
-                    author: '本书编写组',
-                    cover: '/static/img/1.png',
-                    price: '6.80',
-                    originalPrice: '36.80',
-                    desc: '“山河岁月”以宏大的历史视野,讲述了... '
-                },
-                {
-                    id: 5,
-                    title: '山河岁月',
-                    author: '本书编写组',
-                    cover: '/static/img/1.png',
-                    price: '6.80',
-                    originalPrice: '36.80',
-                    desc: '“山河岁月”以宏大的历史视野,讲述了... '
-                }
-            ]
+            bookList: [],
+            navbarBackground: 'transparent',
+            navbarTitleColor: '#ffffff',
+            navbarIconColor: '#ffffff'
+        }
+    },
+    onPageScroll(e) {
+        if (e.scrollTop > 50) {
+            this.navbarBackground = '#ffffff';
+            this.navbarTitleColor = '#000000';
+            this.navbarIconColor = '#000000';
+        } else {
+            this.navbarBackground = 'transparent';
+            this.navbarTitleColor = '#ffffff';
+            this.navbarIconColor = '#ffffff';
         }
     },
-    mounted() {
-        // Open service popup by default for testing
-        this.$nextTick(() => {
-            this.$refs.servicePopup.open();
-        });
+    onLoad(options) {
+        this.keyword = options.keyword ? decodeURIComponent(options.keyword) : '';
+        this.loadData();
     },
     methods: {
+        loadData() {
+            this.$u.api.getSearchKeywordAjax({
+                keyword: this.keyword,
+                pageNum: this.pageNum,
+                pageSize: this.pageSize
+            }).then(res => {
+                const rows = res.data.rows || [];
+                if (this.pageNum === 1) {
+                    this.bookList = rows;
+                } else {
+                    this.bookList = [...this.bookList, ...rows];
+                }
+            })
+        },
         goBack() {
             uni.navigateBack();
         },

+ 189 - 175
pages-sell/pages/search.vue

@@ -42,8 +42,8 @@
                 </image>
             </view>
             <view class="tags-list" v-if="hotVisible">
-                <view class="tag-item" v-for="(item, index) in hotList" :key="index"
-                    @click="doSearch(item.name)" :class="item.className">
+                <view class="tag-item" v-for="(item, index) in hotList" :key="index" @click="doSearch(item.name)"
+                    :class="item.className">
                     <image v-if="item.tag === 'NEW'" src="/pages-sell/static/search/icon-new.png" class="tag-icon-new"
                         mode="heightFix"></image>
                     <image v-if="item.tag === 'HOT'" src="/pages-sell/static/search/icon-fire.png" class="tag-icon-fire"
@@ -57,7 +57,8 @@
         <view class="red-packet-float" @click="openPacket">
             <view class="time-badge">
                 <text>剩</text>
-                <u-count-down :timestamp="timestamp" separator="colon" color="#DF1407" bg-color="transparent" font-size="18" separator-size="18" separator-color="#DF1407"></u-count-down>
+                <u-count-down :timestamp="timestamp" separator="colon" color="#DF1407" bg-color="transparent"
+                    font-size="18" separator-size="18" separator-color="#DF1407"></u-count-down>
             </view>
             <image src="/pages-sell/static/search/icon-red-packet.png" class="packet-img" mode="aspectFit"></image>
         </view>
@@ -68,220 +69,233 @@
 </template>
 
 <script>
-import Navbar from '@/components/navbar/navbar.vue';
-import PacketDialog from '@/pages-sell/components/packet-dialog/index.vue';
+    import Navbar from '@/components/navbar/navbar.vue';
+    import PacketDialog from '@/pages-sell/components/packet-dialog/index.vue';
 
-export default {
-    components: {
-        Navbar,
-        PacketDialog
-    },
-    data() {
-        return {
-            keyword: '',
-            historyList: ['本朝纲目', '千金方', '墨菲定律', '狂人日记', '鲁迅经典', '资治通鉴'],
-            hotVisible: true,
-            hotList: [
-                { name: '毛概 2023', tag: 'NEW' },
-                { name: '吸引力法则', tag: 'HOT' },
-                { name: '神农本草经书', tag: '' }
-            ],
-            timestamp: 86400, // 24 hours countdown
-            showPacketDialog: false
-        }
-    },
-    methods: {
-        onSearch() {
-            if (!this.keyword.trim()) return;
-            this.doSearch(this.keyword);
-        },
-        doSearch(key) {
-            console.log('Search:', key);
-            this.keyword = key;
-            // Navigate to result page or show results
-            uni.showToast({
-                title: '搜索: ' + key,
-                icon: 'none'
-            });
-            uni.navigateTo({
-                url: '/pages-sell/pages/search-result?keyword=' + key
-            });
+    export default {
+        components: {
+            Navbar,
+            PacketDialog
         },
-        clearHistory() {
-            uni.showModal({
-                title: '提示',
-                content: '确定清空搜索历史吗?',
-                success: (res) => {
-                    if (res.confirm) {
-                        this.historyList = [];
-                    }
-                }
-            });
-        },
-        toggleHot() {
-            this.hotVisible = !this.hotVisible;
+        data() {
+            return {
+                keyword: '',
+                historyList: [],
+                hotVisible: true,
+                hotList: [],
+                timestamp: 86400, // 24 hours countdown
+                showPacketDialog: false
+            }
         },
-        openPacket() {
-            this.showPacketDialog = true;
+        onShow() {
+            this.getHistoryData();
+            this.getHotData();
         },
-        closePacket() {
-            this.showPacketDialog = false;
+        methods: {
+            getHistoryData() {
+                this.$u.api.getSearchHistoryAjax().then(res => {
+                    this.historyList = res.data || [];
+                })
+            },
+            getHotData() {
+                this.$u.api.getHotSearchListAjax().then(res => {
+                    this.hotList = res.data.map((v, index) => ({
+                        name: v,
+                        className: index % 2 == 0 ? 'hot-tag' : 'history-tag'
+                    })) || [];
+                })
+            },
+            onSearch() {
+                if (!this.keyword.trim()) return;
+                this.doSearch(this.keyword);
+            },
+            doSearch(key) {
+                console.log('Search:', key);
+                this.keyword = key;
+                // Navigate to result page or show results
+                uni.showToast({
+                    title: '搜索: ' + key,
+                    icon: 'none'
+                });
+                uni.navigateTo({
+                    url: '/pages-sell/pages/search-result?keyword=' + key
+                });
+            },
+            clearHistory() {
+                uni.showModal({
+                    title: '提示',
+                    content: '确定清空搜索历史吗?',
+                    success: (res) => {
+                        if (res.confirm) {
+                            this.historyList = [];
+                        }
+                    }
+                });
+            },
+            toggleHot() {
+                this.hotVisible = !this.hotVisible;
+            },
+            openPacket() {
+                this.showPacketDialog = true;
+            },
+            closePacket() {
+                this.showPacketDialog = false;
+            }
         }
     }
-}
 </script>
 
 <style lang="scss" scoped>
-.search-page {
-    min-height: 100vh;
-    background-color: #fff;
-    font-family: 'Source Han Sans SC', sans-serif;
-}
-
-.search-area {
-    padding: 30rpx 30rpx;
-}
-
-.search-box {
-    display: flex;
-    align-items: center;
-    background-color: #F6F6F6;
-    border-radius: 40rpx;
-    height: 80rpx;
-    padding: 0 10rpx 0 30rpx;
-
-    .search-icon-left {
-        width: 36rpx;
-        height: 36rpx;
-        margin-right: 20rpx;
+    .search-page {
+        min-height: 100vh;
+        background-color: #fff;
+        font-family: 'Source Han Sans SC', sans-serif;
     }
 
-    .search-input {
-        flex: 1;
-        height: 100%;
-        font-size: 28rpx;
-        color: #333;
+    .search-area {
+        padding: 30rpx 30rpx;
     }
 
-    .search-btn {
-        width: 120rpx;
-        height: 60rpx;
-        background: linear-gradient(0deg, #37C148 0%, #6ADD83 100%);
-        border-radius: 48rpx; // 24px
+    .search-box {
         display: flex;
         align-items: center;
-        justify-content: center;
-        margin-left: 20rpx;
+        background-color: #F6F6F6;
+        border-radius: 40rpx;
+        height: 80rpx;
+        padding: 0 10rpx 0 30rpx;
 
-        text {
-            color: #fff;
-            font-size: 28rpx;
-            font-weight: 500;
-        }
-    }
-}
-
-.section {
-    padding: 30rpx;
-
-    .section-header {
-        display: flex;
-        justify-content: space-between;
-        align-items: center;
-        margin-bottom: 30rpx;
-
-        .left {
-            display: flex;
-            align-items: center;
+        .search-icon-left {
+            width: 36rpx;
+            height: 36rpx;
+            margin-right: 20rpx;
         }
 
-        .title {
-            font-size: 32rpx;
-            font-weight: bold;
+        .search-input {
+            flex: 1;
+            height: 100%;
+            font-size: 28rpx;
             color: #333;
         }
 
-        .icon-delete,
-        .icon-view {
-            width: 32rpx;
-            height: 32rpx;
-        }
+        .search-btn {
+            width: 120rpx;
+            height: 60rpx;
+            background: linear-gradient(0deg, #37C148 0%, #6ADD83 100%);
+            border-radius: 48rpx; // 24px
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            margin-left: 20rpx;
 
-        .icon-fire {
-            width: 36rpx;
-            height: 36rpx;
-            margin-right: 10rpx;
+            text {
+                color: #fff;
+                font-size: 28rpx;
+                font-weight: 500;
+            }
         }
     }
 
-    .tags-list {
-        display: flex;
-        flex-wrap: wrap;
+    .section {
+        padding: 30rpx;
 
-        .tag-item {
-            background: #F8F7F0;
-            border-radius: 30rpx;
-            padding: 8rpx 30rpx;
-            font-size: 26rpx;
-            color: #666;
-            margin-right: 20rpx;
-            margin-bottom: 20rpx;
+        .section-header {
             display: flex;
+            justify-content: space-between;
             align-items: center;
+            margin-bottom: 30rpx;
 
-            &.history-tag {
-                background-color: #EBF8EE;
+            .left {
+                display: flex;
+                align-items: center;
             }
 
-            &.hot-item {
-                background: #F5F3F9;
+            .title {
+                font-size: 32rpx;
+                font-weight: bold;
+                color: #333;
             }
 
-            .tag-icon-new {
-                height: 16rpx;
-                margin-right: 8rpx;
+            .icon-delete,
+            .icon-view {
+                width: 32rpx;
+                height: 32rpx;
             }
 
-            .tag-icon-fire {
-                width: 28rpx;
-                height: 28rpx;
-                margin-right: 8rpx;
+            .icon-fire {
+                width: 36rpx;
+                height: 36rpx;
+                margin-right: 10rpx;
+            }
+        }
+
+        .tags-list {
+            display: flex;
+            flex-wrap: wrap;
+
+            .tag-item {
+                background: #F8F7F0;
+                border-radius: 30rpx;
+                padding: 8rpx 30rpx;
+                font-size: 26rpx;
+                color: #666;
+                margin-right: 20rpx;
+                margin-bottom: 20rpx;
+                display: flex;
+                align-items: center;
+
+                &.history-tag {
+                    background-color: #EBF8EE;
+                }
+
+                &.hot-item {
+                    background: #F5F3F9;
+                }
+
+                .tag-icon-new {
+                    height: 16rpx;
+                    margin-right: 8rpx;
+                }
+
+                .tag-icon-fire {
+                    width: 28rpx;
+                    height: 28rpx;
+                    margin-right: 8rpx;
+                }
             }
         }
     }
-}
 
-.red-packet-float {
-    position: fixed;
-    bottom: 200rpx;
-    right: 40rpx;
-    z-index: 100;
-    display: flex;
-    flex-direction: column;
-    align-items: center;
-    
-    .time-badge {
-        background: #FFE173;
-        color: #DF1407;
-        font-size: 18rpx;
-        padding: 4rpx 10rpx;
-        border-radius: 10rpx;
-        position: absolute;
-        top: -40rpx;
-        right: -20rpx;
-        white-space: nowrap;
-        z-index: 2;
+    .red-packet-float {
+        position: fixed;
+        bottom: 200rpx;
+        right: 40rpx;
+        z-index: 100;
         display: flex;
+        flex-direction: column;
         align-items: center;
-        
-        text {
-            margin-right: 4rpx;
+
+        .time-badge {
+            background: #FFE173;
+            color: #DF1407;
+            font-size: 18rpx;
+            padding: 4rpx 10rpx;
+            border-radius: 10rpx;
+            position: absolute;
+            top: -40rpx;
+            right: -20rpx;
+            white-space: nowrap;
+            z-index: 2;
+            display: flex;
+            align-items: center;
+
+            text {
+                margin-right: 4rpx;
+            }
         }
-    }
 
-    .packet-img {
-        width: 100rpx;
-        height: 120rpx;
+        .packet-img {
+            width: 100rpx;
+            height: 120rpx;
+        }
     }
-}
 </style>