Browse Source

feat(搜索): 实现搜索结果页面及功能

- 新增搜索结果页面,包含搜索栏、筛选栏和书籍列表
- 添加热门推荐组件和书籍推荐组件
- 支持导航到搜索结果页并显示搜索关键词
- 优化导航栏样式配置,增加标题大小和颜色自定义
- 添加相关图标资源文件
ylong 1 tuần trước cách đây
mục cha
commit
65af36e14b

+ 15 - 3
components/navbar/navbar.vue

@@ -3,9 +3,9 @@
 		:back-icon-name="backIconName"
 		:title="title"
 		:custom-back="backFunction"
-		:back-icon-color="$appTheme.appThemeTextBlackColor"
-		:title-color="$appTheme.appThemeTextBlackColor"
-		:title-size="32"
+		:back-icon-color="backIconColor"
+		:title-color="titleColor"
+		:title-size="titleSize"
 		:is-back="isback"
 		:back-icon-size="36"
 		:border-bottom="false"
@@ -22,11 +22,23 @@ export default {
 			type: String,
 			default: 'arrow-left'
 		},
+		titleSize: {
+			type: Number,
+			default: 32
+		},
 		// 标题
 		title: {
 			type: String,
 			default: ''
 		},
+		titleColor: {
+			type: String,
+			default: '$appTheme.appThemeTextBlackColor'
+		},
+		backIconColor: {
+			type: String,
+			default: '$appTheme.appThemeTextBlackColor'
+		},
 		// 自定义返回
 		backFunction: {
 			type: Function,

+ 139 - 0
pages-sell/components/hot-recommend-item/index.vue

@@ -0,0 +1,139 @@
+<template>
+	<view class="hot-item">
+		<image :src="item.cover" class="book-cover" mode="aspectFill"></image>
+		<view class="info-right">
+			<view class="info-top">
+				<text class="title">{{ item.title }}</text>
+				<view class="price-row">
+					<text class="currency">¥</text>
+					<text class="price">{{ item.price }}</text>
+				</view>
+
+				<view class="flex space-between">
+					<view class="discount-tag" v-if="item.discountDesc">
+						<text class="discount">{{ item.discount }}</text>
+						<text class="discount-desc">{{ item.discountDesc }}</text>
+					</view>
+
+					<view class="btn-cart" @click.stop="handleAddToCart">
+						<text>加入购物车</text>
+					</view>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+export default {
+	name: 'HotRecommendItem',
+	props: {
+		item: {
+			type: Object,
+			required: true,
+			default: () => ({})
+		}
+	},
+	methods: {
+		handleAddToCart() {
+			this.$emit('add-cart', this.item);
+		}
+	}
+}
+</script>
+
+<style lang="scss" scoped>
+.hot-item {
+	display: flex;
+	border-radius: 16rpx;
+
+	.book-cover {
+		width: 140rpx;
+		height: 180rpx;
+		border-radius: 4rpx;
+		background-color: #f5f5f5;
+		margin-right: 20rpx;
+		flex-shrink: 0;
+	}
+
+	.info-right {
+		flex: 1;
+
+		.info-top {
+			height: 100%;
+			display: flex;
+			flex-direction: column;
+			justify-content: space-between;
+
+			.title {
+				font-size: 30rpx;
+				font-weight: bold;
+				color: #333;
+				margin-bottom: 10rpx;
+				display: block;
+			}
+
+			.price-row {
+				display: flex;
+				align-items: baseline;
+				margin-bottom: 10rpx;
+
+				.currency {
+					font-size: 32rpx;
+					color: #D81A00;
+					font-weight: bold;
+				}
+
+				.price {
+					font-size: 36rpx;
+					color: #D81A00;
+					font-weight: bold;
+				}
+			}
+
+			.discount-tag {
+				display: inline-block;
+				border-radius: 10rpx;
+				font-family: Source Han Sans SC;
+				font-weight: 500;
+				font-size: 22rpx;
+				height: 40rpx;
+				line-height: 40rpx;
+				background-color: #fff;
+				border: 2rpx solid #D81A00;
+				box-sizing: border-box;
+				overflow: auto;
+
+				.discount {
+					background: #D81A00;
+					color: #fff;
+					display: inline-block;
+					padding: 0 12rpx;
+					box-sizing: border-box;
+				}
+
+				.discount-desc {
+					color: #D81A00;
+					padding: 0 10rpx;
+				}
+			}
+		}
+
+		.btn-cart {
+			align-self: flex-end;
+			background: #38C248;
+			border-radius: 30rpx;
+			height: 60rpx;
+			display: flex;
+			align-items: center;
+			justify-content: center;
+			padding: 0 20rpx;
+
+			text {
+				font-size: 28rpx;
+				color: #fff;
+			}
+		}
+	}
+}
+</style>

+ 6 - 6
pages-sell/components/recommend-item/index.vue

@@ -1,17 +1,13 @@
 <template>
 	<view class="recommend-item">
 		<!-- Main Info Row -->
-		<view class="main-info">
+		<view class="main-info" :style="{ 'margin-bottom': showDesc ? '30rpx' : '0' }">
 			<image :src="item.cover" class="book-cover" mode="aspectFill"></image>
 
 			<view class="info-right">
 				<view class="title-author">
 					<view class="title-row">
 						<text class="title">{{ item.title }}</text>
-						<!-- Assuming share icon is only at page top, based on typical designs, 
-						     but if it's per item, I'd add it here. 
-						     The prompt image 1 shows a share icon at the top right of the page header. 
-						     I'll leave it out of the item for now unless I see otherwise. -->
 					</view>
 					<text class="author">{{ item.author }}</text>
 				</view>
@@ -31,7 +27,7 @@
 		</view>
 
 		<!-- Description Row -->
-		<view class="desc-section">
+		<view class="desc-section" v-if="showDesc">
 			<view class="desc-header">
 				<text class="label">简介</text>
 				<view class="indicator"></view>
@@ -48,6 +44,10 @@ export default {
 		item: {
 			type: Object,
 			required: true
+		},
+		showDesc: {
+			type: Boolean,
+			default: true
 		}
 	},
 	methods: {

+ 259 - 0
pages-sell/pages/search-result.vue

@@ -0,0 +1,259 @@
+<template>
+    <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>
+
+        <!-- Custom Header -->
+        <view class="search-bar-wrapper">
+            <u-search style="width: 100%;" v-model="keyword" placeholder="书名/作者/ISBN" :show-action="true" action-text="取消"
+                :action-style="{ color: '#fff' }" bg-color="#fff" shape="round" :clearabled="true"
+                search-icon="/pages-sell/static/search-icon.png" @custom="goBack" @search="onSearch"></u-search>
+        </view>
+
+        <!-- Banner -->
+        <view class="banner-section">
+            <image src="/pages-sell/static/top-banner.png" class="top-banner" mode="widthFix"></image>
+        </view>
+
+        <!-- Content Area -->
+        <view class="content-area">
+            <!-- Everyone is watching -->
+            <view class="section-block">
+                <text class="section-title">大家都在看</text>
+                <HotRecommendItem :item="hotBook" @add-cart="addToCart"></HotRecommendItem>
+            </view>
+
+            <!-- Filter Bar -->
+            <view class="filter-bar">
+                <view class="filter-item active">
+                    <text>综合</text>
+                    <view class="triangle-icon"></view>
+                </view>
+                <view class="filter-item">
+                    <text>销量</text>
+                </view>
+                <view class="filter-item">
+                    <text>价格</text>
+                    <view class="sort-icons">
+                        <image src="/pages-sell/static/search-result/icon-top.png" class="icon-sort"></image>
+                        <image src="/pages-sell/static/search-result/icon-bottom.png" class="icon-sort"></image>
+                    </view>
+                </view>
+                <view class="filter-item">
+                    <text>筛选</text>
+                    <image src="/pages-sell/static/search-result/icon-filter.png" class="icon-filter"></image>
+                </view>
+            </view>
+
+            <!-- Book List -->
+            <view class="book-list">
+                <RecommendItem v-for="(item, index) in bookList" :key="index" :item="item" @add-cart="addToCart" :show-desc="false">
+                </RecommendItem>
+            </view>
+        </view>
+    </view>
+</template>
+
+<script>
+import RecommendItem from '../components/recommend-item/index.vue';
+import HotRecommendItem from '../components/hot-recommend-item/index.vue';
+import Navbar from '@/components/navbar/navbar.vue';
+
+export default {
+    components: {
+        RecommendItem,
+        HotRecommendItem,
+        Navbar
+    },
+    data() {
+        return {
+            keyword: '习近平新时代思想',
+            hotBook: {
+                id: 1,
+                title: '山河岁月',
+                cover: '/static/img/1.png', // Assuming a placeholder or from static
+                price: '6.80',
+                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: '“山河岁月”以宏大的历史视野,讲述了... '
+                }
+            ]
+        }
+    },
+    methods: {
+        goBack() {
+            uni.navigateBack();
+        },
+        onSearch(val) {
+            console.log('Search:', val);
+        },
+        addToCart(item) {
+            uni.showToast({
+                title: '已加入购物车',
+                icon: 'success'
+            });
+        }
+    }
+}
+</script>
+
+<style lang="scss" scoped>
+.search-result-page {
+    min-height: 100vh;
+    background-color: #F6F6F6;
+    font-family: 'Source Han Sans SC', sans-serif;
+    position: relative;
+}
+
+/* 顶部大背景图 */
+.top-bg-image {
+    position: fixed;
+    top: 0;
+    left: 0;
+    width: 100%;
+    z-index: 0;
+    display: block;
+}
+
+.search-bar-wrapper {
+    position: relative;
+    z-index: 100;
+    display: flex;
+    align-items: center;
+    padding: 0 30rpx;
+    height: 88rpx;
+    width: 100%;
+}
+
+.banner-section {
+    position: relative;
+    width: 100%;
+    z-index: 1;
+    padding: 10rpx 30rpx;
+
+    .top-banner {
+        width: 100%;
+        display: block;
+    }
+}
+
+.content-area {
+    position: relative;
+    z-index: 2;
+    padding: 30rpx 30rpx;
+    border-radius: 30rpx 30rpx 0 0;
+    min-height: 500rpx;
+
+    .section-block {
+        margin-bottom: 30rpx;
+        background-color: #fff;
+        padding: 30rpx 24rpx;
+        border-radius: 20rpx;
+
+        .section-title {
+            font-size: 32rpx;
+            font-weight: bold;
+            color: #333;
+            margin-bottom: 20rpx;
+            display: block;
+        }
+    }
+}
+
+.filter-bar {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    margin-bottom: 20rpx;
+
+    .filter-item {
+        display: flex;
+        align-items: center;
+        font-size: 28rpx;
+        color: #666;
+
+        &.active {
+            color: #333;
+            font-weight: bold;
+
+            .triangle-icon {
+                border-top-color: #333;
+            }
+        }
+
+        text {
+            margin-right: 6rpx;
+        }
+
+        .triangle-icon {
+            width: 0;
+            height: 0;
+            border-left: 8rpx solid transparent;
+            border-right: 8rpx solid transparent;
+            border-top: 10rpx solid #666;
+        }
+
+        .sort-icons {
+            display: flex;
+            flex-direction: column;
+            margin-left: 4rpx;
+
+            .icon-sort {
+                width: 12rpx;
+                height: 8rpx;
+                margin: 2rpx 0;
+            }
+        }
+
+        .icon-filter {
+            width: 24rpx;
+            height: 24rpx;
+            margin-left: 4rpx;
+        }
+    }
+}
+
+.book-list {
+    padding-bottom: 40rpx;
+    background: #fff;
+    border-radius: 20rpx;
+    padding: 0 24rpx;
+}
+</style>

+ 3 - 0
pages-sell/pages/search.vue

@@ -103,6 +103,9 @@ export default {
                 title: '搜索: ' + key,
                 icon: 'none'
             });
+            uni.navigateTo({
+                url: '/pages-sell/pages/search-result?keyword=' + key
+            });
         },
         clearHistory() {
             uni.showModal({

BIN
pages-sell/static/search-result/icon-bottom.png


BIN
pages-sell/static/search-result/icon-filter.png


BIN
pages-sell/static/search-result/icon-top.png


+ 6 - 1
pages.json

@@ -302,7 +302,12 @@
                 {
                     "path": "pages/search",
                     "style": {
-                        "navigationBarTitleText": "搜索",
+                        "navigationStyle": "custom"
+                    }
+                },
+                {
+                    "path": "pages/search-result",
+                    "style": {
                         "navigationStyle": "custom"
                     }
                 }