consumer模块完成度85%,连接服务器supabase,新建相关表
This commit is contained in:
@@ -244,85 +244,7 @@
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 智能推荐 -->
|
||||
<view class="smart-recommend">
|
||||
<view class="section-header">
|
||||
<view class="title-section">
|
||||
<text class="section-icon">✨</text>
|
||||
<text class="section-title">智能推荐</text>
|
||||
</view>
|
||||
<view class="recommend-filters">
|
||||
<text
|
||||
v-for="filter in recommendFilters"
|
||||
:key="filter.id"
|
||||
:class="['filter-item', { active: activeFilter === filter.id }]"
|
||||
@click="switchFilter(filter.id)"
|
||||
>
|
||||
{{ filter.name }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="recommend-grid">
|
||||
<view
|
||||
v-for="product in recommendedProducts"
|
||||
:key="product.id"
|
||||
class="recommend-product"
|
||||
@click="navigateToProduct(product)"
|
||||
>
|
||||
<view class="product-image-container">
|
||||
<image
|
||||
class="product-image"
|
||||
:src="product.image"
|
||||
mode="aspectFill"
|
||||
/>
|
||||
<view class="product-tags">
|
||||
<text v-if="product.tag" class="product-tag">{{ product.tag }}</text>
|
||||
<text v-if="product.featured" class="featured-tag">{{ product.featured }}</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<view class="product-details">
|
||||
<text class="product-title">{{ product.name }}</text>
|
||||
<text class="product-specification">{{ product.specification }}</text>
|
||||
|
||||
<view class="product-rating">
|
||||
<view class="rating-stars">
|
||||
<text class="star-icon">⭐</text>
|
||||
<text class="rating-value">{{ product.rating }}</text>
|
||||
</view>
|
||||
<text class="reviews-count">{{ product.reviews }}条评价</text>
|
||||
</view>
|
||||
|
||||
<view class="price-section">
|
||||
<view class="current-price">
|
||||
<text class="price-symbol">¥</text>
|
||||
<text class="price-value">{{ product.price }}</text>
|
||||
</view>
|
||||
<text class="original-price" v-if="product.originalPrice > product.price">
|
||||
¥{{ product.originalPrice }}
|
||||
</text>
|
||||
</view>
|
||||
|
||||
<view class="product-actions">
|
||||
<view class="add-to-cart" @click.stop="addToCart(product)">
|
||||
<text class="cart-icon">🛒</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 加载状态 -->
|
||||
<view v-if="loading" class="loading-state">
|
||||
<view class="loading-spinner"></view>
|
||||
<text class="loading-text">加载中...</text>
|
||||
</view>
|
||||
|
||||
<view v-if="!hasMore && recommendedProducts.length > 0" class="no-more">
|
||||
<text class="no-more-text">--- 已加载全部内容 ---</text>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 智能推荐模块已隐藏 -->
|
||||
|
||||
<!-- 健康提醒 -->
|
||||
<view class="health-reminder">
|
||||
@@ -347,6 +269,8 @@
|
||||
<script setup lang="uts">
|
||||
import { ref, reactive, onMounted } from 'vue'
|
||||
import { onShow } from '@dcloudio/uni-app'
|
||||
import supabaseService from '@/utils/supabaseService.uts'
|
||||
import type { Product, Category } from '@/utils/supabaseService.uts'
|
||||
|
||||
// 响应式数据
|
||||
const statusBarHeight = ref(0)
|
||||
@@ -359,9 +283,8 @@ const activeFilter = ref('recommend')
|
||||
const currentPage = ref(1)
|
||||
|
||||
// 数据源
|
||||
const allProducts = ref<any[]>([])
|
||||
const hotProducts = ref<any[]>([])
|
||||
const recommendedProducts = ref<any[]>([])
|
||||
const hotProducts = ref<Product[]>([])
|
||||
const recommendedProducts = ref<Product[]>([])
|
||||
|
||||
// 屏幕尺寸检测
|
||||
const isMobile = ref(false)
|
||||
@@ -372,35 +295,18 @@ const lastScrollTop = ref(0)
|
||||
const scrollThreshold = 30 // 降低滚动阈值,使其更灵敏
|
||||
const scrollingUp = ref(false)
|
||||
|
||||
// 分类数据
|
||||
const categories = [
|
||||
{ id: 'cold', name: '感冒发烧', icon: '🤧', desc: '解热镇痛', color: '#2196F3' },
|
||||
{ id: 'stomach', name: '肠胃用药', icon: '🤢', desc: '消化系统', color: '#4CAF50' },
|
||||
{ id: 'pain', name: '止痛消炎', icon: '💊', desc: '镇痛消炎', color: '#F44336' },
|
||||
{ id: 'skin', name: '皮肤用药', icon: '🤕', desc: '皮肤护理', color: '#9C27B0' },
|
||||
{ id: 'vitamin', name: '维生素', icon: '🍊', desc: '营养补充', color: '#FF9800' },
|
||||
{ id: 'chronic', name: '慢性病', icon: '🫀', desc: '长期管理', color: '#795548' },
|
||||
{ id: 'child', name: '儿童用药', icon: '👶', desc: '儿童专用', color: '#00BCD4' },
|
||||
{ id: 'external', name: '外用药品', icon: '🧴', desc: '外用制剂', color: '#8BC34A' },
|
||||
{ id: 'device', name: '医疗器械', icon: '🩺', desc: '医疗设备', color: '#607D8B' },
|
||||
{ id: 'health', name: '健康食品', icon: '🥗', desc: '保健食品', color: '#FFC107' }
|
||||
]
|
||||
// 分类数据 - 从Supabase获取
|
||||
const categories = ref<Category[]>([])
|
||||
|
||||
// 排序标签
|
||||
const sortTabs = [
|
||||
{ id: 'recommend', name: '智能推荐' },
|
||||
{ id: 'sales', name: '销量' },
|
||||
{ id: 'price', name: '价格' },
|
||||
{ id: 'new', name: '新品' },
|
||||
{ id: 'recommend', name: '推荐' }
|
||||
{ id: 'discount', name: '特价' }
|
||||
]
|
||||
|
||||
// 推荐筛选器
|
||||
const recommendFilters = [
|
||||
{ id: 'recommend', name: '智能推荐' },
|
||||
{ id: 'hot', name: '热门商品' },
|
||||
{ id: 'discount', name: '限时优惠' },
|
||||
{ id: 'quality', name: '品质优选' }
|
||||
]
|
||||
|
||||
// 健康资讯
|
||||
const healthNews = [
|
||||
@@ -424,100 +330,89 @@ const healthNews = [
|
||||
}
|
||||
]
|
||||
|
||||
// 获取分类数据
|
||||
const loadCategories = async () => {
|
||||
try {
|
||||
const categoriesData = await supabaseService.getCategories()
|
||||
// 映射字段:将description映射为desc,保持与原有结构兼容
|
||||
categories.value = categoriesData.map((cat: any) => ({
|
||||
id: cat.id,
|
||||
name: cat.name,
|
||||
icon: cat.icon || '📦',
|
||||
desc: cat.description || cat.desc || '',
|
||||
color: cat.color || '#4CAF50'
|
||||
}))
|
||||
} catch (error) {
|
||||
console.error('加载分类数据失败:', error)
|
||||
// 如果加载失败,使用默认分类作为后备
|
||||
categories.value = [
|
||||
{ id: 'cold', name: '感冒发烧', icon: '🤧', desc: '解热镇痛', color: '#2196F3' },
|
||||
{ id: 'stomach', name: '肠胃用药', icon: '🤢', desc: '消化系统', color: '#4CAF50' },
|
||||
{ id: 'pain', name: '止痛消炎', icon: '💊', desc: '镇痛消炎', color: '#F44336' },
|
||||
{ id: 'skin', name: '皮肤用药', icon: '🤕', desc: '皮肤护理', color: '#9C27B0' },
|
||||
{ id: 'vitamin', name: '维生素', icon: '🍊', desc: '营养补充', color: '#FF9800' }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// 获取热销商品(根据当前排序方式)
|
||||
const loadHotProducts = async () => {
|
||||
try {
|
||||
let products: Product[] = []
|
||||
const limit = 6
|
||||
|
||||
console.log('加载热销商品,当前排序方式:', activeSort.value)
|
||||
|
||||
switch (activeSort.value) {
|
||||
case 'sales':
|
||||
console.log('调用 getHotProducts')
|
||||
products = await supabaseService.getHotProducts(limit)
|
||||
break
|
||||
case 'price':
|
||||
console.log('调用 getProductsByPrice')
|
||||
// 按价格升序(从低到高)
|
||||
products = await supabaseService.getProductsByPrice(limit, true)
|
||||
break
|
||||
case 'new':
|
||||
console.log('调用 getProductsByNewest')
|
||||
// 按创建时间,最新的在前
|
||||
products = await supabaseService.getProductsByNewest(limit)
|
||||
break
|
||||
case 'recommend':
|
||||
console.log('调用 getRecommendedProducts')
|
||||
// 推荐商品(带badge的商品)
|
||||
products = await supabaseService.getRecommendedProducts(limit)
|
||||
break
|
||||
case 'discount':
|
||||
console.log('调用 getDiscountProducts')
|
||||
// 特价商品(badge为'特价')
|
||||
products = await supabaseService.getDiscountProducts(limit)
|
||||
break
|
||||
default:
|
||||
console.log('调用默认 getHotProducts')
|
||||
products = await supabaseService.getHotProducts(limit)
|
||||
}
|
||||
|
||||
console.log('加载到的商品数量:', products.length)
|
||||
hotProducts.value = products
|
||||
} catch (error) {
|
||||
console.error('加载热销商品失败:', error)
|
||||
hotProducts.value = []
|
||||
}
|
||||
}
|
||||
|
||||
// 获取推荐商品
|
||||
const loadRecommendedProducts = async (limit: number = 6) => {
|
||||
recommendedProducts.value = await supabaseService.getRecommendedProducts(limit)
|
||||
}
|
||||
|
||||
// 初始化数据
|
||||
const initData = () => {
|
||||
const manufacturers = ['修正药业', '白云山', '养生堂', '三九医药', '同仁堂', '云南白药', '拜耳', '辉瑞']
|
||||
const names = ['布洛芬', '板蓝根', '维生素C', '胃康灵', '阿莫西林', '连花清瘟', '氨溴索', '氯雷他定', '感冒灵', '健胃消食片', '阿司匹林', '蒙脱石散']
|
||||
const tags = ['处方药', '中成药', '止咳化痰', '抗过敏', '感冒发烧', '肠胃用药', '消炎镇痛']
|
||||
const featureds = ['医生推荐', '热销爆款', '家庭必备', '季节必备', '店长推荐']
|
||||
|
||||
const products = [] as any[]
|
||||
for (let i = 0; i < 50; i++) {
|
||||
const nameIdx = Math.floor(Math.random() * names.length)
|
||||
const name = names[nameIdx]
|
||||
const price = parseFloat((10 + Math.random() * 100).toFixed(1))
|
||||
const originalPrice = parseFloat((price * (1.1 + Math.random() * 0.5)).toFixed(1))
|
||||
const sales = Math.floor(Math.random() * 5000)
|
||||
|
||||
// 随机店铺ID,避免全部是同一家
|
||||
const randomShopSuffix = Math.floor(Math.random() * 20) + 1
|
||||
|
||||
products.push({
|
||||
id: `prod_${i}`,
|
||||
shopId: `shop_${randomShopSuffix}`,
|
||||
shopName: manufacturers[Math.floor(Math.random() * manufacturers.length)] + '官方旗舰店',
|
||||
name: name + (Math.random() > 0.5 ? '胶囊' : '颗粒'),
|
||||
specification: Math.random() > 0.5 ? '0.3g*24粒' : '10g*10袋',
|
||||
price: price,
|
||||
originalPrice: originalPrice,
|
||||
image: '/static/images/default-product.png',
|
||||
manufacturer: manufacturers[Math.floor(Math.random() * manufacturers.length)],
|
||||
sales: sales,
|
||||
rating: (3.5 + Math.random() * 1.5).toFixed(1),
|
||||
reviews: Math.floor(Math.random() * 500),
|
||||
tag: tags[Math.floor(Math.random() * tags.length)],
|
||||
featured: Math.random() > 0.7 ? featureds[Math.floor(Math.random() * featureds.length)] : '',
|
||||
badge: sales > 3000 ? '热销' : (price < 20 ? '特价' : (Math.random() > 0.8 ? '新品' : '')),
|
||||
// Attributes for filtering
|
||||
isNew: Math.random() > 0.8,
|
||||
isRecommend: Math.random() > 0.6,
|
||||
isHot: sales > 2000,
|
||||
isDiscount: (originalPrice - price) > 15,
|
||||
isQuality: price > 60
|
||||
})
|
||||
}
|
||||
allProducts.value = products
|
||||
|
||||
filterHotProducts()
|
||||
filterRecommendedProducts()
|
||||
const initData = async () => {
|
||||
await loadCategories()
|
||||
await loadHotProducts()
|
||||
await loadRecommendedProducts()
|
||||
}
|
||||
|
||||
// 筛选热销商品
|
||||
const filterHotProducts = () => {
|
||||
let list = [...allProducts.value]
|
||||
|
||||
if (activeSort.value === 'sales') {
|
||||
list.sort((a, b) => b.sales - a.sales)
|
||||
} else if (activeSort.value === 'price') {
|
||||
list.sort((a, b) => a.price - b.price)
|
||||
} else if (activeSort.value === 'new') {
|
||||
list = list.filter(p => p.isNew)
|
||||
} else if (activeSort.value === 'recommend') {
|
||||
list = list.filter(p => p.isRecommend)
|
||||
}
|
||||
|
||||
// 如果筛选后数量不足4个,补足
|
||||
if (list.length < 4) {
|
||||
const remaining = allProducts.value.filter(p => !list.includes(p))
|
||||
list = [...list, ...remaining]
|
||||
}
|
||||
|
||||
hotProducts.value = list.slice(0, 4)
|
||||
}
|
||||
|
||||
// 筛选推荐商品
|
||||
const filterRecommendedProducts = () => {
|
||||
let list = [...allProducts.value]
|
||||
|
||||
if (activeFilter.value === 'hot') {
|
||||
list = list.filter(p => p.isHot)
|
||||
} else if (activeFilter.value === 'discount') {
|
||||
list = list.filter(p => p.isDiscount)
|
||||
} else if (activeFilter.value === 'quality') {
|
||||
list = list.filter(p => p.isQuality)
|
||||
} else {
|
||||
// 默认随机排序
|
||||
list.sort(() => Math.random() - 0.5)
|
||||
}
|
||||
|
||||
// 如果筛选后数量不足4个,补足
|
||||
if (list.length < 4) {
|
||||
const remaining = allProducts.value.filter(p => !list.includes(p))
|
||||
list = [...list, ...remaining]
|
||||
}
|
||||
|
||||
recommendedProducts.value = list.slice(0, 4)
|
||||
}
|
||||
|
||||
// 家庭常备药
|
||||
const familyItems = [
|
||||
@@ -572,9 +467,9 @@ const familyItems = [
|
||||
]
|
||||
|
||||
// 生命周期
|
||||
onMounted(() => {
|
||||
onMounted(async () => {
|
||||
initPage()
|
||||
initData()
|
||||
await initData()
|
||||
})
|
||||
|
||||
// 页面显示时重置状态
|
||||
@@ -689,13 +584,15 @@ const switchCategory = (category: any) => {
|
||||
// 切换排序
|
||||
const switchSort = (sortId: string) => {
|
||||
activeSort.value = sortId
|
||||
filterHotProducts()
|
||||
// 重新加载热销商品,排序由 Supabase 服务处理
|
||||
loadHotProducts()
|
||||
}
|
||||
|
||||
// 切换筛选器
|
||||
const switchFilter = (filterId: string) => {
|
||||
activeFilter.value = filterId
|
||||
filterRecommendedProducts()
|
||||
// 重新加载推荐商品,筛选由 Supabase 服务处理
|
||||
loadRecommendedProducts()
|
||||
}
|
||||
|
||||
// 查看新闻详情
|
||||
@@ -718,27 +615,33 @@ const onRefresh = () => {
|
||||
}
|
||||
|
||||
// 加载更多
|
||||
const loadMore = () => {
|
||||
const loadMore = async () => {
|
||||
if (loading.value || !hasMore.value) return
|
||||
|
||||
loading.value = true
|
||||
setTimeout(() => {
|
||||
// 模拟加载更多数据
|
||||
const newProducts = [...recommendedProducts].map((item, index) => ({
|
||||
...item,
|
||||
id: `new${index}`,
|
||||
price: Math.floor(item.price * 0.9 + Math.random() * 10)
|
||||
}))
|
||||
try {
|
||||
// 增加限制以加载更多推荐商品
|
||||
const currentLimit = recommendedProducts.value.length + 6
|
||||
await loadRecommendedProducts(currentLimit)
|
||||
|
||||
// 实际项目中应该合并数据
|
||||
loading.value = false
|
||||
hasMore.value = recommendedProducts.length < 20
|
||||
// 假设如果返回的商品数量小于请求的限制,则没有更多数据
|
||||
if (recommendedProducts.value.length < currentLimit) {
|
||||
hasMore.value = false
|
||||
}
|
||||
|
||||
uni.showToast({
|
||||
title: '加载完成',
|
||||
icon: 'success'
|
||||
})
|
||||
}, 2000)
|
||||
} catch (error) {
|
||||
console.error('加载更多失败:', error)
|
||||
uni.showToast({
|
||||
title: '加载失败',
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
// 添加到购物车
|
||||
|
||||
Reference in New Issue
Block a user