Files
apple 079076a70e miao33: 从 main 同步 single_uniapp22miao,dart-sass 兼容修复,DEPLOY.md 更新
- 从 main 获取 single_uniapp22miao 子项目
- dart-sass: /deep/ -> ::v-deep,calc 运算符加空格
- DEPLOY.md 采用 shccd159 版本(4 子项目架构说明)

Made-with: Cursor
2026-03-16 11:16:42 +08:00

384 lines
7.9 KiB
Vue
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="search-page">
<!-- 搜索栏 -->
<view class="search-bar">
<view class="search-input-wrapper">
<text class="search-icon">🔍</text>
<input
v-model="keyword"
placeholder="搜索商品"
confirm-type="search"
@confirm="handleSearch"
class="search-input"
focus
/>
<text v-if="keyword" class="clear-icon" @click="clearKeyword">×</text>
</view>
<text class="cancel-btn" @click="goBack">取消</text>
</view>
<!-- 搜索历史 -->
<view class="history-section" v-if="!keyword && searchHistory.length > 0">
<view class="section-header">
<text class="title">搜索历史</text>
<text class="clear-btn" @click="clearHistory">清空</text>
</view>
<view class="history-list">
<view
v-for="(item, index) in searchHistory"
:key="index"
class="history-item"
@click="searchByHistory(item)"
>
{{ item }}
</view>
</view>
</view>
<!-- 热门搜索 -->
<view class="hot-section" v-if="!keyword">
<view class="section-header">
<text class="title">热门搜索</text>
</view>
<view class="hot-list">
<view
v-for="(item, index) in hotKeywords"
:key="index"
class="hot-item"
@click="searchByHot(item)"
>
{{ item }}
</view>
</view>
</view>
<!-- 搜索结果 -->
<scroll-view
v-if="keyword"
scroll-y
class="result-scroll"
@scrolltolower="loadMore"
>
<view class="result-list">
<view
v-for="(goods, index) in goodsList"
:key="index"
class="goods-item"
@click="goToGoodsDetail(goods)"
>
<image :src="goods.image" class="goods-image"></image>
<view class="goods-info">
<view class="goods-name">{{ goods.name }}</view>
<view class="goods-price">¥{{ goods.price }}</view>
</view>
</view>
<!-- 加载更多 -->
<view class="load-more" v-if="goodsList.length > 0">
<text v-if="loading">加载中...</text>
<text v-else-if="noMore">没有更多了</text>
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="goodsList.length === 0 && !loading && searched">
<text class="icon">😕</text>
<text class="text">未找到相关商品</text>
</view>
</view>
</scroll-view>
</view>
</template>
<script>
export default {
data() {
return {
keyword: '',
searchHistory: [],
hotKeywords: ['手机', '电脑', '相机', '耳机', '手表'],
goodsList: [],
page: 1,
limit: 20,
loading: false,
noMore: false,
searched: false
}
},
onLoad() {
this.loadSearchHistory();
},
methods: {
// 加载搜索历史
loadSearchHistory() {
const history = uni.getStorageSync('searchHistory') || [];
this.searchHistory = history;
},
// 保存搜索历史
saveSearchHistory(keyword) {
let history = uni.getStorageSync('searchHistory') || [];
history = history.filter(item => item !== keyword);
history.unshift(keyword);
history = history.slice(0, 10);
uni.setStorageSync('searchHistory', history);
this.searchHistory = history;
},
// 清空搜索词
clearKeyword() {
this.keyword = '';
this.goodsList = [];
this.searched = false;
},
// 清空历史
clearHistory() {
uni.showModal({
title: '提示',
content: '确定清空搜索历史吗?',
success: (res) => {
if (res.confirm) {
uni.removeStorageSync('searchHistory');
this.searchHistory = [];
}
}
});
},
// 搜索
handleSearch() {
if (!this.keyword.trim()) return;
this.saveSearchHistory(this.keyword);
this.page = 1;
this.noMore = false;
this.goodsList = [];
this.searchGoods();
},
// 通过历史搜索
searchByHistory(keyword) {
this.keyword = keyword;
this.handleSearch();
},
// 通过热门搜索
searchByHot(keyword) {
this.keyword = keyword;
this.handleSearch();
},
// 搜索商品
async searchGoods() {
if (this.loading || this.noMore) return;
this.loading = true;
this.searched = true;
try {
const res = await this.$http.get('/api/goods/list', {
page: this.page,
limit: this.limit,
keyword: this.keyword
});
if (res.code === 0) {
const list = res.data.list || [];
if (list.length < this.limit) {
this.noMore = true;
}
this.goodsList = this.page === 1 ? list : [...this.goodsList, ...list];
}
} catch (error) {
console.error('搜索失败:', error);
} finally {
this.loading = false;
}
},
// 加载更多
loadMore() {
if (!this.loading && !this.noMore) {
this.page++;
this.searchGoods();
}
},
// 去商品详情
goToGoodsDetail(goods) {
uni.navigateTo({
url: `/pages/sub-pages/good/good-detail?id=${goods.id}`
});
},
// 返回
goBack() {
uni.navigateBack();
}
}
}
</script>
<style lang="scss" scoped>
.search-page {
height: 100vh;
display: flex;
flex-direction: column;
background-color: #f5f5f5;
}
.search-bar {
display: flex;
align-items: center;
padding: 20rpx 30rpx;
background-color: #fff;
.search-input-wrapper {
flex: 1;
display: flex;
align-items: center;
height: 70rpx;
padding: 0 20rpx;
background-color: #f5f5f5;
border-radius: 35rpx;
margin-right: 20rpx;
.search-icon {
font-size: 32rpx;
margin-right: 10rpx;
}
.search-input {
flex: 1;
height: 100%;
font-size: 28rpx;
}
.clear-icon {
font-size: 48rpx;
color: #999;
line-height: 1;
}
}
.cancel-btn {
font-size: 28rpx;
color: #333;
}
}
.history-section,
.hot-section {
padding: 30rpx;
background-color: #fff;
margin-bottom: 20rpx;
.section-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20rpx;
.title {
font-size: 28rpx;
font-weight: bold;
color: #333;
}
.clear-btn {
font-size: 24rpx;
color: #999;
}
}
}
.history-list,
.hot-list {
display: flex;
flex-wrap: wrap;
gap: 20rpx;
}
.history-item,
.hot-item {
padding: 15rpx 30rpx;
background-color: #f5f5f5;
border-radius: 40rpx;
font-size: 26rpx;
color: #666;
}
.result-scroll {
flex: 1;
}
.result-list {
padding: 20rpx 30rpx;
}
.goods-item {
display: flex;
padding: 30rpx;
background-color: #fff;
border-radius: 20rpx;
margin-bottom: 20rpx;
.goods-image {
width: 160rpx;
height: 160rpx;
border-radius: 8rpx;
margin-right: 20rpx;
background-color: #f5f5f5;
}
.goods-info {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
.goods-name {
font-size: 28rpx;
color: #333;
line-height: 1.4;
}
.goods-price {
font-size: 32rpx;
font-weight: bold;
color: #FF4757;
}
}
}
.load-more {
padding: 30rpx;
text-align: center;
font-size: 26rpx;
color: #999;
}
.empty-state {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 200rpx 0;
.icon {
font-size: 120rpx;
margin-bottom: 20rpx;
}
.text {
font-size: 28rpx;
color: #999;
}
}
</style>