consumer模块完成95%,在和商家端对接聊天购物闭环

This commit is contained in:
2026-02-06 17:10:31 +08:00
parent 06b7369494
commit e2f1dfb097
1454 changed files with 5425 additions and 210555 deletions

View File

@@ -16,7 +16,7 @@
:value="searchKeyword"
@input="onInput"
@confirm="onSearch"
placeholder="请输入品名称、症状或品牌"
placeholder="请输入品名称、店铺"
placeholder-class="placeholder"
:focus="autoFocus"
/>
@@ -152,8 +152,31 @@
<!-- 搜索结果 -->
<view v-if="showResults" class="search-results">
<!-- 店铺搜索结果 -->
<view v-if="searchShopResults.length > 0" class="shop-results-section">
<view class="section-top">
<text class="result-title-sm">相关店铺</text>
</view>
<scroll-view scroll-x class="shop-list-scroll">
<view class="shop-list-row">
<view
v-for="shop in searchShopResults"
:key="shop.id"
class="shop-card"
@click="viewShopDetail(shop)"
>
<image class="shop-logo" :src="shop.logo" mode="aspectFill" />
<view class="shop-info">
<text class="shop-name-txt">{{ shop.name }}</text>
<text class="shop-products-txt">共{{ shop.productCount }}件商品</text>
</view>
</view>
</view>
</scroll-view>
</view>
<view class="results-header">
<text class="results-title">搜索结果</text>
<text class="results-title">商品结果</text>
<view class="filter-tabs">
<text
class="filter-tab"
@@ -250,23 +273,15 @@ const hotSearchList = ref<any[]>([])
const guessList = ref<any[]>([])
const allGuessItems = ref<any[]>([]) // 缓存所有猜你喜欢商品
const searchResults = ref<any[]>([])
const searchShopResults = ref<any[]>([]) // 搜索到的店铺
// 搜索建议
const searchSuggestions = computed(() => {
if (!searchKeyword.value) return []
// 简单模拟
return [
`${searchKeyword.value}胶囊`,
`${searchKeyword.value}颗粒`,
`${searchKeyword.value}片`,
`儿童${searchKeyword.value}`
]
})
onMounted(() => {
initPage()
})
const initPage = () => {
try {
const systemInfo = uni.getSystemInfoSync()
@@ -287,9 +302,11 @@ const initPage = () => {
const keyword = decodeURIComponent(options['keyword'])
searchKeyword.value = keyword
if (options['type'] === 'family') {
// 如果是家庭常备药类型,直接添加到历史并搜索
addToHistory(keyword)
if (options['type'] === 'family' || options['type'] === 'brand') {
// 如果是家庭常备药或品牌类型,直接添加到历史并搜索
if (options['type'] === 'family') {
addToHistory(keyword)
}
// 立即显示结果区域并设置为加载中
showResults.value = true
loading.value = true
@@ -397,12 +414,44 @@ const deleteHistoryItem = (index: number) => {
saveSearchHistory()
}
// 搜索建议 - 改为实时获取
const searchSuggestions = ref<string[]>([])
let suggestTimer = 0
const fetchSuggestions = async (kw: string) => {
if (!kw || showResults.value) return
// 简单搜索前5个相关商品作为建议
try {
const res = await supabaseService.searchProducts(kw.trim(), 1, 5)
if (res.data.length > 0) {
// 去重
const names = res.data.map((p:any) => p.name as string)
// @ts-ignore
searchSuggestions.value = [...new Set(names)]
} else {
searchSuggestions.value = []
}
} catch(e) {
searchSuggestions.value = []
}
}
// 搜索逻辑
const onInput = (e: any) => {
searchKeyword.value = e.detail.value
if (!searchKeyword.value) {
const val = e.detail.value
searchKeyword.value = val
if (!val) {
showResults.value = false
searchSuggestions.value = []
return
}
// Debounce suggestion search
if (suggestTimer > 0) clearTimeout(suggestTimer)
suggestTimer = setTimeout(() => {
fetchSuggestions(val)
}, 300)
}
const clearSearch = () => {
@@ -460,9 +509,29 @@ const performSearch = async () => {
}
try {
const response = await supabaseService.searchProducts(keyword, currentPage.value, 20, sortBy, ascending)
// 并行请求:商品搜索 + 店铺搜索
const [prodResp, shopResp] = await Promise.all([
supabaseService.searchProducts(keyword, currentPage.value, 20, sortBy, ascending),
// 只有第一页搜索且非价格排序时搜索店铺,避免重复和无关搜索
currentPage.value === 1 && activeSort.value === 'default'
? supabaseService.searchShops(keyword)
: Promise.resolve({ data: [], total: 0, page: 1, limit: 0, hasmore: false })
])
searchResults.value = response.data.map((p: any) => {
// 处理店铺结果
if (shopResp.data.length > 0) {
searchShopResults.value = shopResp.data.map((s: any) => ({
id: s.id,
name: s.shop_name,
logo: s.shop_logo || '/static/shop_logo_default.png',
productCount: s.product_count || 0
}))
} else {
searchShopResults.value = []
}
// 处理商品结果
searchResults.value = prodResp.data.map((p: any) => {
let tag = ''
if (p.tags) {
try {
@@ -482,7 +551,7 @@ const performSearch = async () => {
}
})
hasMore.value = response.hasmore
hasMore.value = prodResp.hasmore
} catch(e) {
console.error('Search failed', e)
} finally {
@@ -578,6 +647,12 @@ const viewProductDetail = (item: any) => {
})
}
const viewShopDetail = (shop: any) => {
uni.navigateTo({
url: `/pages/mall/consumer/shop-detail?id=${shop.id}`
})
}
// 添加到购物车 - 搜索列表无法选择规格,跳转详情页
const addToCart = (product: any) => {
uni.showToast({ title: '请选择规格', icon: 'none' })
@@ -607,7 +682,15 @@ const goBack = () => {
searchKeyword.value = ''
} else {
// 如果在搜索初始页,则返回上一页
uni.navigateBack()
const pages = getCurrentPages()
if (pages.length > 1) {
uni.navigateBack()
} else {
// 如果只有一页(由于深链接或重定向),返回首页
uni.switchTab({
url: '/pages/mall/consumer/index'
})
}
}
}
</script>
@@ -621,6 +704,75 @@ const goBack = () => {
flex-direction: column;
}
/* 店铺搜索结果 */
.shop-results-section {
background-color: #fff;
margin-bottom: 10px;
padding: 10px 0;
}
.section-top {
padding: 0 12px 10px;
}
.result-title-sm {
font-size: 14px;
font-weight: bold;
color: #333;
}
.shop-list-scroll {
width: 100%;
white-space: nowrap;
}
.shop-list-row {
display: flex;
flex-direction: row;
padding: 0 12px;
}
.shop-card {
display: flex;
flex-direction: column;
align-items: center;
width: 80px;
margin-right: 15px;
background-color: #f9f9f9;
padding: 10px 5px;
border-radius: 8px;
}
.shop-logo {
width: 48px;
height: 48px;
border-radius: 24px;
margin-bottom: 5px;
border: 1px solid #f0f0f0;
background-color: white;
}
.shop-info {
width: 100%;
text-align: center;
}
.shop-name-txt {
font-size: 12px;
color: #333;
width: 100%;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
display: block;
margin-bottom: 2px;
}
.shop-products-txt {
font-size: 10px;
color: #999;
}
/* 头部样式 */
.search-header {
background-color: #ffffff;