consumer模块完成90%,前端完成supabase对接
This commit is contained in:
@@ -229,7 +229,7 @@
|
||||
|
||||
<script setup lang="uts">
|
||||
import { ref, reactive, onMounted, computed } from 'vue'
|
||||
import supabaseService from '@/utils/supabaseService.uts'
|
||||
import { supabaseService } from '@/utils/supabaseService.uts'
|
||||
import type { Product } from '@/utils/supabaseService.uts'
|
||||
|
||||
// 状态定义
|
||||
@@ -248,28 +248,9 @@ const priceSortAsc = ref(false) // 价格排序是否为升序
|
||||
const searchHistory = ref<string[]>([])
|
||||
const hotSearchList = ref<any[]>([])
|
||||
const guessList = ref<any[]>([])
|
||||
const allGuessItems = ref<any[]>([]) // 缓存所有猜你喜欢商品
|
||||
const searchResults = ref<any[]>([])
|
||||
|
||||
// 模拟数据库
|
||||
const mockDatabase = {
|
||||
hot: [
|
||||
{ keyword: '感冒灵', hot: true },
|
||||
{ keyword: '布洛芬', hot: true },
|
||||
{ keyword: '口罩', hot: true },
|
||||
{ keyword: '维生素C', hot: false },
|
||||
{ keyword: '板蓝根', hot: false },
|
||||
{ keyword: '创可贴', hot: false },
|
||||
],
|
||||
guess: [
|
||||
{ id: 'g1', name: '医用外科口罩', price: 19.9, image: 'https://picsum.photos/200/200?random=1', sales: '1万+' },
|
||||
{ id: 'g2', name: '酒精消毒液', price: 9.9, image: 'https://picsum.photos/200/200?random=2', sales: '5000+' },
|
||||
{ id: 'g3', name: '电子体温计', price: 29.9, image: 'https://picsum.photos/200/200?random=3', sales: '2000+' },
|
||||
{ id: 'g4', name: '碘伏消毒液', price: 5.5, image: 'https://picsum.photos/200/200?random=4', sales: '1000+' },
|
||||
{ id: 'g5', name: '退热贴', price: 15.8, image: 'https://picsum.photos/200/200?random=5', sales: '3000+' },
|
||||
{ id: 'g6', name: '棉签', price: 3.9, image: 'https://picsum.photos/200/200?random=6', sales: '8000+' },
|
||||
]
|
||||
}
|
||||
|
||||
// 搜索建议
|
||||
const searchSuggestions = computed(() => {
|
||||
if (!searchKeyword.value) return []
|
||||
@@ -327,22 +308,35 @@ const initPage = () => {
|
||||
}
|
||||
|
||||
// 加载基础数据
|
||||
const loadData = () => {
|
||||
// loading.value = true // 不使用全局loading,避免影响搜索状态
|
||||
const loadData = async () => {
|
||||
isError.value = false
|
||||
|
||||
// 模拟网络请求
|
||||
setTimeout(() => {
|
||||
try {
|
||||
loadSearchHistory()
|
||||
hotSearchList.value = mockDatabase.hot
|
||||
guessList.value = mockDatabase.guess
|
||||
// loading.value = false // 不使用全局loading
|
||||
} catch (e) {
|
||||
isError.value = true
|
||||
// loading.value = false
|
||||
}
|
||||
}, 500)
|
||||
try {
|
||||
loadSearchHistory()
|
||||
// 获取热门商品作为热门搜索推荐和猜你喜欢
|
||||
// 获取更多数据以便"换一批"
|
||||
const hotProducts = await supabaseService.getHotProducts(30)
|
||||
|
||||
hotSearchList.value = hotProducts.slice(0, 10).map((p: any) => ({
|
||||
keyword: p.name,
|
||||
hot: true
|
||||
}))
|
||||
|
||||
allGuessItems.value = hotProducts.map((p: any) => ({
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
price: p.base_price,
|
||||
image: p.main_image_url || '/static/default.jpg',
|
||||
sales: typeof p.sale_count === 'number' ? p.sale_count : 0
|
||||
}))
|
||||
|
||||
// 初始显示随机6个
|
||||
refreshGuessListItems()
|
||||
|
||||
} catch (e) {
|
||||
console.error('Load data failed', e)
|
||||
isError.value = true
|
||||
}
|
||||
}
|
||||
|
||||
// 点击重试
|
||||
@@ -441,13 +435,12 @@ const selectSuggestion = (suggestion: string) => {
|
||||
|
||||
const currentPage = ref(1)
|
||||
|
||||
const performSearch = () => {
|
||||
const performSearch = async () => {
|
||||
// 再次强制设置状态,确保万无一失
|
||||
showResults.value = true
|
||||
loading.value = true
|
||||
// 重置页码
|
||||
currentPage.value = 1
|
||||
// 保持旧数据直到新数据回来,或者依靠 loading 状态完全遮罩
|
||||
|
||||
// 使用 Supabase 搜索真实数据
|
||||
const keyword = searchKeyword.value.trim()
|
||||
@@ -462,25 +455,39 @@ const performSearch = () => {
|
||||
if (activeSort.value === 'price') {
|
||||
sortBy = 'price'
|
||||
ascending = priceSortAsc.value
|
||||
}
|
||||
} else if (activeSort.value === 'default') {
|
||||
sortBy = 'default'
|
||||
}
|
||||
|
||||
supabaseService.searchProducts(keyword, currentPage.value, 20, sortBy, ascending)
|
||||
.then((response) => {
|
||||
searchResults.value = response.data as any[]
|
||||
hasMore.value = response.hasmore
|
||||
loading.value = false
|
||||
|
||||
// 如果无结果,显示空状态
|
||||
if (searchResults.value.length === 0) {
|
||||
// empty-result 组件会自动显示
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('搜索失败:', error)
|
||||
loading.value = false
|
||||
// 可以显示错误提示,但为了用户体验,先不显示
|
||||
// 保持搜索结果为空,让empty-result显示
|
||||
})
|
||||
try {
|
||||
const response = await supabaseService.searchProducts(keyword, currentPage.value, 20, sortBy, ascending)
|
||||
|
||||
searchResults.value = response.data.map((p: any) => {
|
||||
let tag = ''
|
||||
if (p.tags) {
|
||||
try {
|
||||
const tags = (typeof p.tags === 'string') ? JSON.parse(p.tags) : p.tags
|
||||
if (Array.isArray(tags) && tags.length > 0) tag = String(tags[0])
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
return {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
image: p.main_image_url || '/static/default.jpg',
|
||||
price: p.base_price,
|
||||
specification: p.specification || '标准规格',
|
||||
tag: tag,
|
||||
sales: p.sale_count || 0
|
||||
}
|
||||
})
|
||||
|
||||
hasMore.value = response.hasmore
|
||||
} catch(e) {
|
||||
console.error('Search failed', e)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 切换排序
|
||||
@@ -499,7 +506,7 @@ const switchSort = (type: string) => {
|
||||
performSearch()
|
||||
}
|
||||
|
||||
const loadMore = () => {
|
||||
const loadMore = async () => {
|
||||
if (loading.value || !hasMore.value || !searchKeyword.value.trim()) return
|
||||
loading.value = true
|
||||
|
||||
@@ -513,79 +520,70 @@ const loadMore = () => {
|
||||
if (activeSort.value === 'price') {
|
||||
sortBy = 'price'
|
||||
ascending = priceSortAsc.value
|
||||
}
|
||||
} else if (activeSort.value === 'default') {
|
||||
sortBy = 'default'
|
||||
}
|
||||
|
||||
supabaseService.searchProducts(keyword, currentPage.value, 20, sortBy, ascending)
|
||||
.then((response) => {
|
||||
searchResults.value.push(...(response.data as any[]))
|
||||
hasMore.value = response.hasmore
|
||||
loading.value = false
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('加载更多失败:', error)
|
||||
loading.value = false
|
||||
// 加载失败时,假设没有更多数据
|
||||
hasMore.value = false
|
||||
})
|
||||
try {
|
||||
const response = await supabaseService.searchProducts(keyword, currentPage.value, 20, sortBy, ascending)
|
||||
const newItems = response.data.map((p: any) => {
|
||||
let tag = ''
|
||||
if (p.tags) {
|
||||
try {
|
||||
const tags = (typeof p.tags === 'string') ? JSON.parse(p.tags) : p.tags
|
||||
if (Array.isArray(tags) && tags.length > 0) tag = String(tags[0])
|
||||
} catch(e) {}
|
||||
}
|
||||
|
||||
return {
|
||||
id: p.id,
|
||||
name: p.name,
|
||||
image: p.main_image_url || '/static/default.jpg',
|
||||
price: p.base_price,
|
||||
specification: p.specification || '标准规格',
|
||||
tag: tag,
|
||||
sales: p.sale_count || 0
|
||||
}
|
||||
})
|
||||
searchResults.value.push(...newItems)
|
||||
hasMore.value = response.hasmore
|
||||
} catch(e) {
|
||||
console.error('Load more failed', e)
|
||||
hasMore.value = false
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
const refreshGuessList = () => {
|
||||
uni.showLoading({ title: '刷新中' })
|
||||
setTimeout(() => {
|
||||
guessList.value = guessList.value.sort(() => Math.random() - 0.5)
|
||||
uni.hideLoading()
|
||||
}, 500)
|
||||
setTimeout(() => {
|
||||
refreshGuessListItems()
|
||||
uni.hideLoading()
|
||||
}, 500)
|
||||
}
|
||||
|
||||
const refreshGuessListItems = () => {
|
||||
if (allGuessItems.value.length > 0) {
|
||||
// 简单的随机乱序并取前6个
|
||||
const shuffled = [...allGuessItems.value].sort(() => Math.random() - 0.5)
|
||||
guessList.value = shuffled.slice(0, 6)
|
||||
}
|
||||
}
|
||||
|
||||
const viewProductDetail = (item: any) => {
|
||||
// 跳转详情页逻辑
|
||||
console.log('查看商品', item)
|
||||
// 跳转详情页逻辑 - 传递必要的参数作为预加载/fallback
|
||||
uni.navigateTo({
|
||||
url: `/pages/mall/consumer/product-detail?productId=${item.id}&price=${item.price}&originalPrice=${item.original_price || ''}&name=${encodeURIComponent(item.name)}&image=${encodeURIComponent(item.image)}`
|
||||
url: `/pages/mall/consumer/product-detail?productId=${item.id}&price=${item.price}&name=${encodeURIComponent(item.name)}`
|
||||
})
|
||||
}
|
||||
|
||||
// 添加到购物车
|
||||
// 添加到购物车 - 搜索列表无法选择规格,跳转详情页
|
||||
const addToCart = (product: any) => {
|
||||
// 获取现有购物车数据
|
||||
const cartData = uni.getStorageSync('cart')
|
||||
let cartItems: any[] = []
|
||||
|
||||
if (cartData) {
|
||||
try {
|
||||
cartItems = JSON.parse(cartData as string) as any[]
|
||||
} catch (e) {
|
||||
console.error('解析购物车数据失败', e)
|
||||
}
|
||||
}
|
||||
|
||||
// 检查商品是否已存在
|
||||
const existingItem = cartItems.find((item: any) => item.id === product.id)
|
||||
|
||||
if (existingItem) {
|
||||
existingItem.quantity++
|
||||
} else {
|
||||
// 添加新商品
|
||||
cartItems.push({
|
||||
id: product.id,
|
||||
shopId: product.shopId || 'shop_search_default',
|
||||
shopName: product.shopName || (product.tag === '自营' ? '平台自营大药房' : '优质大药房'),
|
||||
name: product.name,
|
||||
price: product.price,
|
||||
image: product.image,
|
||||
spec: product.specification || '默认规格',
|
||||
quantity: 1,
|
||||
selected: true
|
||||
})
|
||||
}
|
||||
|
||||
// 保存回存储
|
||||
uni.setStorageSync('cart', JSON.stringify(cartItems))
|
||||
|
||||
uni.showToast({
|
||||
title: '已添加到购物车',
|
||||
icon: 'success'
|
||||
})
|
||||
uni.showToast({ title: '请选择规格', icon: 'none' })
|
||||
setTimeout(() => {
|
||||
viewProductDetail(product)
|
||||
}, 800)
|
||||
}
|
||||
|
||||
const openCamera = () => {
|
||||
|
||||
Reference in New Issue
Block a user