consumer模块完成95%,在和商家端对接聊天购物闭环
This commit is contained in:
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user