feat(buyer): 增强搜索功能并提升用户体验

- 新增 `getStoreById` 接口方法,用于获取包含评分在内的店铺信息
- `Search.vue` 新增搜索建议面板,展示搜索历史和热词,优化搜索体验
- 新增 `SearchSuggest.vue` 组件,用于展示搜索建议和搜索历史
- `App.vue` 根据路由元信息按条件设置页面标题
- 优化多个组件的布局与样式,让整体风格更统一
- 重构多个组件的跳转逻辑,改用路由跳转(`router.push`)替代新开窗口(`window.open`),提升用户体验
This commit is contained in:
pikachu1995@126.com
2026-10-02 15:26:58 +08:00
parent 4777eb2dd6
commit 8410179885
44 changed files with 2116 additions and 674 deletions

View File

@@ -21,32 +21,34 @@
>
<span :class="{ 'goods-list-tool-active': index === sortIndex }">
{{ item.title }}
<el-icon><ArrowDown /></el-icon>
<el-icon v-if="index === sortIndex" class="sort-arrow"><ArrowDown /></el-icon>
</span>
</li>
<li @click="orderBy('price', 5, 'up')" class="price-sort">
<span :class="{ 'goods-list-tool-active': 5 === sortIndex }">
<li @click="orderBy('price', priceSortIndex)" class="price-sort">
<span :class="{ 'goods-list-tool-active': priceSortIndex === sortIndex }">
价格
<span class="price-arrows">
<el-icon :class="{ 'price-color': sortPriceIndex == 'desc' }"><ArrowUp /></el-icon>
<el-icon :class="{ 'price-color': sortPriceIndex == 'asc' }"><ArrowDown /></el-icon>
<el-icon :class="{ 'is-on': priceSortIndex === sortIndex && sortPriceIndex === 'asc' }"><ArrowUp /></el-icon>
<el-icon :class="{ 'is-on': priceSortIndex === sortIndex && sortPriceIndex === 'desc' }"><ArrowDown /></el-icon>
</span>
</span>
</li>
</ul>
</div>
<!-- 列表 -->
<div class="goods-list">
<empty v-if="goodsList.length === 0" />
<div v-if="searched && !loading && goodsList.length === 0" class="list-empty">
<empty :_Title="emptyTitle" />
<div v-if="recommendList.length" class="recommend-title">为你推荐</div>
</div>
<div class="goods-list" v-if="displayGoods.length">
<div
v-else
class="goods-show-info"
v-for="(item, index) in goodsList"
:key="index"
v-for="(item, index) in displayGoods"
:key="item.id || index"
@click="goGoodsDetail(item.id, item.goodsId)"
>
<div class="goods-show-img">
<img :src="item.thumbnail" />
<GoodsThumb :src="item.thumbnail" :alt="item.goodsName" />
</div>
<div class="goods-show-price">
<span>
@@ -85,7 +87,7 @@
</div>
</div>
</div>
<div class="goods-page">
<div class="goods-page" v-if="total > 0">
<el-pagination
v-model:current-page="params.pageNumber"
v-model:page-size="params.pageSize"
@@ -105,6 +107,7 @@
import { Message } from "@/utils/message";
import { ArrowDown, ArrowUp } from '@element-plus/icons-vue';
import GoodsClassNav from "@/components/nav/GoodsClassNav";
import GoodsThumb from "@/components/goods/GoodsThumb.vue";
import * as apiGoods from "@/api/goods";
export default {
name: "GoodsList",
@@ -115,7 +118,10 @@ export default {
data() {
return {
sortIndex: 0, // 排序状态
priceSortIndex: 4,
sortPriceIndex: false, // 判断价格升序还是降序
searched: false,
recommendList: [],
goodsTool: [
// 排序类型
{ title: "综合", en: "" },
@@ -154,6 +160,16 @@ export default {
this.getGoodsList();
},
},
computed: {
displayGoods() {
if (this.goodsList.length) return this.goodsList;
return this.searched && !this.loading ? this.recommendList : [];
},
emptyTitle() {
const keyword = this.params.keyword;
return keyword ? `没有找到与“${keyword}”相关的商品` : "暂无商品";
},
},
methods: {
// 搜索
handleSearch(key) {
@@ -204,11 +220,10 @@ export default {
Message.warning("店铺信息不存在");
return;
}
const routeUrl = this.$router.resolve({
this.$router.push({
path: "/merchant",
query: { id },
});
window.open(routeUrl.href, "_blank");
},
// 分页 修改页码
changePageNum(val) {
@@ -230,14 +245,28 @@ export default {
.then((res) => {
this.loading = false;
if (res.success) {
this.goodsList = res.result.records;
this.goodsList = res.result.records || [];
this.total = res.result.total;
if (!this.goodsList.length) this.loadRecommend();
}
})
.catch(() => {
this.goodsList = [];
})
.finally(() => {
this.loading = false;
this.searched = true;
});
},
loadRecommend() {
if (this.recommendList.length) return;
apiGoods
.goodsList({ pageNumber: 1, pageSize: 10, sort: "buyCount", order: "desc" })
.then((res) => {
if (res.success) this.recommendList = res.result.records || [];
})
.catch(() => {});
},
getParams(val) {
// 筛选条件回显
Object.assign(this.params, val);
@@ -256,6 +285,7 @@ export default {
},
components: {
GoodsClassNav,
GoodsThumb,
ArrowDown,
ArrowUp,
},
@@ -395,8 +425,12 @@ export default {
}
}
.price-color {
color: #b3b3b3;
.el-icon {
color: #c8c8c8;
}
.el-icon.is-on {
color: $theme_color;
}
}
}
@@ -433,9 +467,30 @@ export default {
background-color: transparent !important;
font-weight: 600;
.price-color {
color: $theme_color !important;
.sort-arrow {
color: $theme_color;
}
.price-arrows .el-icon {
color: #c8c8c8;
}
.price-arrows .el-icon.is-on {
color: $theme_color;
}
}
.list-empty {
background: #fff;
border: 1px solid #eee;
border-top: none;
}
.recommend-title {
padding: 4px 16px 12px;
color: #333;
font-size: 16px;
font-weight: 600;
}
.goods-list {