2673 lines
60 KiB
Plaintext
2673 lines
60 KiB
Plaintext
<!-- pages/mall/consumer/index.uvue -->
|
||
<template>
|
||
<view class="medic-home">
|
||
<!-- 智能顶部导航栏 - 添加滚动隐藏效果 -->
|
||
<view
|
||
class="smart-navbar"
|
||
:style="{
|
||
paddingTop: statusBarHeight + 'px',
|
||
transform: showNavbar ? 'translateY(0)' : 'translateY(-100%)'
|
||
}"
|
||
>
|
||
<view class="search-container">
|
||
<view class="search-box" @click="navigateToSearch" :style="{ height: '30px' }">
|
||
<!-- 模拟输入框 -->
|
||
<text class="search-placeholder">请输入药品名称、症状或品牌</text>
|
||
|
||
<!-- 扫码图标 -->
|
||
<view class="nav-icon-btn" @click.stop="onScan">
|
||
<text class="nav-icon">🔳</text>
|
||
</view>
|
||
|
||
<!-- 相机图标 -->
|
||
<view class="nav-camera-btn" @click.stop="onCamera">
|
||
<text class="nav-camera-icon">📷</text>
|
||
</view>
|
||
|
||
<!-- 搜索按钮 -->
|
||
<view class="nav-inner-search-btn" :style="{ height: '22px' }">
|
||
<text class="nav-inner-search-text">搜索</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 导航栏占位符 - 移除,改为使用 margin-top -->
|
||
<!-- <view class="navbar-placeholder" :style="{ height: (statusBarHeight + 44) + 'px' }"></view> -->
|
||
|
||
<!-- 主内容区 -->
|
||
<scroll-view
|
||
direction="vertical"
|
||
class="main-scroll"
|
||
refresher-enabled
|
||
:refresher-triggered="refreshing"
|
||
:lower-threshold="50"
|
||
@refresherrefresh="onRefresh"
|
||
@scrolltolower="loadMore"
|
||
@scroll="handleScroll"
|
||
>
|
||
<!-- 健康资讯轮播 (Moved Up) -->
|
||
<!-- 健康资讯轮播 (Hidden) -->
|
||
<!--
|
||
<view class="health-news">
|
||
...
|
||
</view>
|
||
-->
|
||
|
||
<!-- 智能健康卡片 (Hidden) -->
|
||
<!-- <view class="smart-health-card" :style="{ marginTop: (statusBarHeight + 44 + 10) + 'px' }">
|
||
<view class="health-content">
|
||
<view class="health-header">
|
||
<text class="health-title">智能健康助手</text>
|
||
<text class="health-subtitle">根据您的健康数据推荐</text>
|
||
</view>
|
||
<view class="health-tips">
|
||
<text class="tip-item">💡 按时用药提醒</text>
|
||
<text class="tip-item">📋 健康记录跟踪</text>
|
||
<text class="tip-item">🩺 在线问诊咨询</text>
|
||
</view>
|
||
</view>
|
||
</view> -->
|
||
|
||
<!-- 智能分类网格 - 完全响应式 -->
|
||
<view class="smart-categories" :style="{ marginTop: (statusBarHeight + 44 + 10) + 'px' }">
|
||
<view class="section-header">
|
||
<view class="category-tabs-pills">
|
||
<view :class="['tab-pill', { active: categoryTab == 'category' }]" @click="categoryTab = 'category'">
|
||
<text class="tab-text">智能分类</text>
|
||
</view>
|
||
<view :class="['tab-pill', { active: categoryTab == 'brand' }]" @click="categoryTab = 'brand'">
|
||
<text class="tab-text">品牌甄选</text>
|
||
</view>
|
||
</view>
|
||
<text class="section-desc">快速定位</text>
|
||
</view>
|
||
<view class="category-grid" v-if="categoryTab === 'category'">
|
||
<!-- 一级分类 -->
|
||
<view
|
||
v-for="category in parentCategories"
|
||
:key="category.id"
|
||
class="category-card"
|
||
@click="onParentCategoryClick(category)"
|
||
:style="{ '--card-color': category.color }"
|
||
>
|
||
<view class="card-icon">
|
||
<text class="card-icon-text">{{ category.icon }}</text>
|
||
</view>
|
||
<text class="card-name">{{ category.name }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 二级分类 -->
|
||
<view v-if="categoryTab === 'category' && showSubCategories && subCategories.length > 0" class="sub-category-grid">
|
||
<view class="sub-category-header">
|
||
<text class="sub-category-title">{{ selectedParentCategory?.name }}分类</text>
|
||
<text class="sub-category-close" @click="showSubCategories = false">✕</text>
|
||
</view>
|
||
<view class="sub-category-wrapper">
|
||
<view
|
||
v-for="subCat in subCategories"
|
||
:key="subCat.id"
|
||
class="sub-category-card"
|
||
@click="onSubCategoryClick(subCat)"
|
||
>
|
||
<view class="card-icon">
|
||
<text class="card-icon-text">{{ subCat.icon }}</text>
|
||
</view>
|
||
<text class="card-name">{{ subCat.name }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 品牌列表 -->
|
||
<view class="category-grid" v-if="categoryTab === 'brand'">
|
||
<view
|
||
v-for="brand in brands"
|
||
:key="brand.id"
|
||
class="category-card"
|
||
@click="switchBrand(brand)"
|
||
style="--card-color: #5785e5"
|
||
>
|
||
<view class="card-icon" v-if="brand.logo_url == null || brand.logo_url == ''">
|
||
<text class="card-icon-text">{{ getBrandIcon(brand.name) }}</text>
|
||
</view>
|
||
<image v-else :src="brand.logo_url" mode="aspectFit" class="brand-logo" style="width: 40px; height: 40px; border-radius: 20px;" />
|
||
<text class="card-name">{{ brand.name }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
</view>
|
||
|
||
<!-- 健康资讯轮播 (Original Position - Removed) -->
|
||
|
||
<!-- 智能服务入口 (Hidden) -->
|
||
<!-- <view class="smart-services">
|
||
<view class="services-grid">
|
||
<view class="service-card" @click="navigateToConsultation">
|
||
<view class="service-icon" style="background: #2196F3;">
|
||
<text class="service-icon-text">👨⚕️</text>
|
||
</view>
|
||
<text class="service-name">在线问诊</text>
|
||
<text class="service-desc">三甲医生在线</text>
|
||
</view>
|
||
<view class="service-card" @click="navigateToPrescription">
|
||
<view class="service-icon" style="background: #4CAF50;">
|
||
<text class="service-icon-text">📋</text>
|
||
</view>
|
||
<text class="service-name">电子处方</text>
|
||
<text class="service-desc">医生开方购药</text>
|
||
</view>
|
||
<view class="service-card" @click="navigateToOTC">
|
||
<view class="service-icon" style="background: #FF9800;">
|
||
<text class="service-icon-text">💊</text>
|
||
</view>
|
||
<text class="service-name">非处方药</text>
|
||
<text class="service-desc">安全自主选购</text>
|
||
</view>
|
||
<view class="service-card" @click="navigateToHealthTools">
|
||
<view class="service-icon" style="background: #9C27B0;">
|
||
<text class="service-icon-text">🩺</text>
|
||
</view>
|
||
<text class="service-name">健康工具</text>
|
||
<text class="service-desc">健康管理助手</text>
|
||
</view>
|
||
</view>
|
||
</view> -->
|
||
|
||
<!-- 热销药品专区 -->
|
||
<view class="hot-products">
|
||
<view class="section-header">
|
||
<view class="title-section">
|
||
<text class="section-icon">🔥</text>
|
||
<text class="section-title">热销商品</text>
|
||
</view>
|
||
<view class="sort-tabs">
|
||
<text
|
||
v-for="tab in sortTabs"
|
||
:key="tab.id"
|
||
:class="['sort-tab', { active: activeSort === tab.id }]"
|
||
@click="switchSort(tab.id)"
|
||
>
|
||
{{ tab.name }}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="products-grid">
|
||
<view
|
||
v-for="product in hotProducts"
|
||
:key="product.id"
|
||
class="product-card"
|
||
@click="navigateToProduct(product)"
|
||
>
|
||
<image
|
||
class="product-image"
|
||
:src="product.main_image_url"
|
||
mode="aspectFill"
|
||
/>
|
||
<text class="product-name" :lines="2">{{ product.name }}</text>
|
||
<view class="product-bottom">
|
||
<text class="product-price">¥{{ product.price }}</text>
|
||
<view class="product-add-btn" @click.stop="addToCart(product)">
|
||
<text class="add-icon">+</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<!-- 加载状态提示 -->
|
||
<view class="load-more-status" v-if="loading || showLoadMore">
|
||
<text class="loading-text">正在加载更多商品...</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 家庭常备药 (Hidden) -->
|
||
<!-- <view class="family-medicine">
|
||
<view class="section-header">
|
||
<view class="title-section">
|
||
<text class="section-icon">🏠</text>
|
||
<text class="section-title">家庭常备药</text>
|
||
</view>
|
||
<text class="section-subtitle">守护全家健康</text>
|
||
</view>
|
||
|
||
<view class="family-grid">
|
||
<view
|
||
v-for="item in familyItems"
|
||
:key="item.id"
|
||
class="family-item"
|
||
@click="navigateToCategory(item)"
|
||
>
|
||
<view class="family-icon" :style="{ backgroundColor: item.color }">
|
||
<text class="family-icon-text">{{ item.icon }}</text>
|
||
</view>
|
||
<text class="family-name">{{ item.name }}</text>
|
||
<text class="family-desc">{{ item.desc }}</text>
|
||
</view>
|
||
</view>
|
||
</view> -->
|
||
|
||
<!-- 智能推荐模块已隐藏 -->
|
||
|
||
<!-- 健康提醒 (Hidden) -->
|
||
<!-- <view class="health-reminder">
|
||
<view class="reminder-content">
|
||
<text class="reminder-icon">⏰</text>
|
||
<view class="reminder-text">
|
||
<text class="reminder-title">健康提醒</text>
|
||
<text class="reminder-desc">您有1个待用药提醒,点击查看详情</text>
|
||
</view>
|
||
<view class="reminder-action" @click="navigateToReminders">
|
||
<text class="action-text">查看</text>
|
||
</view>
|
||
</view>
|
||
</view> -->
|
||
|
||
<!-- 底部安全区域 -->
|
||
<view class="safe-area"></view>
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ref, reactive, onMounted } from 'vue'
|
||
import { onShow, onLoad } from '@dcloudio/uni-app'
|
||
import supabaseService from '@/utils/supabaseService.uts'
|
||
import type { Product, Category, Brand } from '@/utils/supabaseService.uts'
|
||
import { getCurrentUser } from '@/utils/store.uts'
|
||
|
||
// 响应式数据
|
||
const statusBarHeight = ref(0)
|
||
const scrollHeight = ref(0)
|
||
const refreshing = ref(false)
|
||
const loading = ref(false)
|
||
const isFirstShow = ref(true)
|
||
const hasMore = ref(true)
|
||
const activeSort = ref('recommend') // 默认展示智能推荐
|
||
const activeFilter = ref('recommend')
|
||
const currentPage = ref(1)
|
||
const priceAscending = ref(true) // 价格排序方向:true=升序,false=降序
|
||
|
||
// 数据源
|
||
const hotProducts = ref<Product[]>([])
|
||
const recommendedProducts = ref<Product[]>([])
|
||
const hotKeywords = ref<string[]>([])
|
||
|
||
// 屏幕尺寸检测
|
||
const isMobile = ref(false)
|
||
const showLoadMore = ref(false)
|
||
|
||
// 导航栏显示控制
|
||
const showNavbar = ref(true)
|
||
const lastScrollTop = ref(0)
|
||
const scrollThreshold = 30 // 降低滚动阈值,使其更灵敏
|
||
const scrollingUp = ref(false)
|
||
|
||
// 分类数据 - 从Supabase获取
|
||
const categoryTab = ref<string>('category')
|
||
const categories = ref<Category[]>([])
|
||
const brands = ref<Brand[]>([])
|
||
|
||
// 一级分类和二级分类
|
||
const parentCategories = ref<Category[]>([])
|
||
const subCategories = ref<Category[]>([])
|
||
const selectedParentCategory = ref<Category | null>(null)
|
||
const showSubCategories = ref(false)
|
||
|
||
|
||
type SortTab = {
|
||
id: string
|
||
name: string
|
||
}
|
||
|
||
// 排序标签
|
||
const sortTabs: SortTab[] = [
|
||
{ id: 'recommend', name: '智能推荐' },
|
||
{ id: 'sales', name: '销量' },
|
||
{ id: 'price', name: '价格' },
|
||
{ id: 'new', name: '新品' },
|
||
{ id: 'discount', name: '特价' }
|
||
]
|
||
|
||
|
||
// 健康资讯
|
||
const healthNews = [
|
||
{
|
||
id: 'news1',
|
||
title: '秋季流感预防指南,科学防护健康过冬',
|
||
tag: '健康科普',
|
||
image: 'https://picsum.photos/800/400?random=health1'
|
||
},
|
||
{
|
||
id: 'news2',
|
||
title: '家庭常备药清单,为家人健康保驾护航',
|
||
tag: '家庭用药',
|
||
image: 'https://picsum.photos/800/400?random=health2'
|
||
},
|
||
{
|
||
id: 'news3',
|
||
title: '慢性病科学管理,提高生活质量',
|
||
tag: '健康管理',
|
||
image: 'https://picsum.photos/800/400?random=health3'
|
||
}
|
||
]
|
||
|
||
// 获取一级分类数据
|
||
const loadCategories = async (): Promise<void> => {
|
||
try {
|
||
const categoriesData = await supabaseService.getParentCategories()
|
||
parentCategories.value = categoriesData
|
||
// 兼容其他使用 categories 的地方
|
||
categories.value = categoriesData
|
||
console.log('一级分类数据:', JSON.stringify(parentCategories.value))
|
||
} catch (error) {
|
||
console.error('加载分类数据失败:', error)
|
||
parentCategories.value = []
|
||
categories.value = []
|
||
}
|
||
}
|
||
|
||
// 获取二级分类数据
|
||
const loadSubCategories = async (parentId: string): Promise<void> => {
|
||
try {
|
||
console.log('[loadSubCategories] 开始加载二级分类, parentId:', parentId)
|
||
const subData = await supabaseService.getSubCategories(parentId)
|
||
console.log('[loadSubCategories] 获取到二级分类数量:', subData.length)
|
||
console.log('[loadSubCategories] 二级分类数据:', JSON.stringify(subData))
|
||
subCategories.value = subData
|
||
} catch (error) {
|
||
console.error('加载子分类数据失败:', error)
|
||
subCategories.value = []
|
||
}
|
||
}
|
||
|
||
// 点击一级分类
|
||
const onParentCategoryClick = async (category: Category): Promise<void> => {
|
||
console.log('[onParentCategoryClick] 点击一级分类:', category.name, 'id:', category.id)
|
||
|
||
// 如果已经选中,则切换显示/隐藏二级分类
|
||
if (selectedParentCategory.value != null && selectedParentCategory.value.id === category.id) {
|
||
console.log('[onParentCategoryClick] 切换显示状态')
|
||
showSubCategories.value = !showSubCategories.value
|
||
return
|
||
}
|
||
|
||
// 选中新的分类
|
||
selectedParentCategory.value = category
|
||
showSubCategories.value = true
|
||
console.log('[onParentCategoryClick] showSubCategories 设置为 true')
|
||
|
||
// 加载二级分类
|
||
await loadSubCategories(category.id)
|
||
|
||
// 如果没有二级分类,直接跳转到分类页
|
||
if (subCategories.value.length == 0) {
|
||
console.log('[onParentCategoryClick] 没有二级分类,直接跳转到分类页')
|
||
uni.setStorageSync('selectedCategory', category.id)
|
||
uni.switchTab({
|
||
url: '/pages/mall/consumer/category'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 点击二级分类
|
||
const onSubCategoryClick = (category: Category): void => {
|
||
// 跳转到分类页面
|
||
uni.setStorageSync('selectedCategory', category.id)
|
||
const timestamp = Date.now()
|
||
const randomParam = Math.random().toString(36).substring(2, 8)
|
||
const url = `/pages/mall/consumer/category?categoryId=${category.id}&name=${encodeURIComponent(category.name)}×tamp=${timestamp}&random=${randomParam}`
|
||
|
||
uni.switchTab({
|
||
url: '/pages/mall/consumer/category'
|
||
})
|
||
}
|
||
|
||
// 获取品牌数据
|
||
const loadBrands = async (): Promise<void> => {
|
||
try {
|
||
const brandsData = await supabaseService.getBrands()
|
||
brands.value = brandsData
|
||
} catch (e) {
|
||
console.error('加载品牌失败:', e)
|
||
brands.value = []
|
||
}
|
||
}
|
||
|
||
// 根据品牌名称获取图标
|
||
const getBrandIcon = (name: string): string => {
|
||
if (name == null || name === '') {
|
||
return '🏢'
|
||
}
|
||
// 常见品牌图标映射(使用数组方式避免 Object.keys 问题)
|
||
const iconKeys = [
|
||
'感冒', '发烧', '咳嗽', '消炎', '维生素', '钙片', '胃药', '止痛', '过敏', '皮肤', '眼药水', '口腔', '血压', '血糖', '血脂', '保健', '养生', '减肥', '美容', '母婴', '儿童', '老人', '男性', '女性', '维生素C', '维生素D', '蛋白粉', '鱼油', '蜂胶', '阿胶', '红枣', '枸杞', '菊花', '金银花', '口罩', '消毒液', '体温计', '创可贴', '棉签',
|
||
'九芝堂', '同仁堂', '云南白药', '东阿阿胶', '太极', '江中', '三九', '华素制药', '汤臣倍健', '白云山', '修正', '葵花', '哈药', '扬子江', '恒瑞', '复星', '辉瑞', '阿斯利康', '罗氏', '默沙东', '赛诺菲', '诺华', '雅培', '雀巢', '蒙牛', '伊利', '海尔', '美的', '飞利浦', '西门子', '松下', '苏泊尔', '九阳', '华为', '小米', '苹果', '三星'
|
||
]
|
||
const iconValues = [
|
||
'💊', '🌡️', '😷', '🔬', '💊', '🦴', '🫁', '💉', '🌸', '🧴', '👁️', '🦷', '❤️', '🩸', '💓', '🧬', '🍵', '⚖️', '💅', '👶', '🧒', '👴', '♂️', '♀️', '🍊', '☀️', '🥛', '🐟', '🐝', '🍯', '🫘', '🌿', '🌼', '🌸', '😷', '🧴', '🌡️', '🩹', '🧺',
|
||
'📜', '🏛️', '⛰️', '🍯', '☯️', '🌿', '9️⃣', '💊', '💪', '⛰️', '🩹', '🌻', '🧪', '🚢', '🔬', '⭐', '🧬', '🧪', '🧬', '💊', '🧬', '🔬', '🏥', '🥣', '🐄', '🥛', '🏠', '❄️', '🪒', '⚡', '🔋', '🍳', '🥛', '📱', '🍚', '🍎', '📱'
|
||
]
|
||
|
||
// 尝试精确匹配
|
||
for (let i = 0; i < iconKeys.length; i++) {
|
||
if (name === iconKeys[i]) {
|
||
return iconValues[i]
|
||
}
|
||
}
|
||
// 尝试模糊匹配
|
||
for (let i = 0; i < iconKeys.length; i++) {
|
||
if (name.indexOf(iconKeys[i]) !== -1) {
|
||
return iconValues[i]
|
||
}
|
||
}
|
||
// 默认返回品牌图标
|
||
return '🏢'
|
||
}
|
||
|
||
// 默认加载商品数量
|
||
const defaultLoadLimit: number = 6
|
||
|
||
// 前置声明内部加载函数
|
||
const doLoadHotProducts = async (targetLimit: number, resolve: (value: void) => void, reject: (reason?: any) => void): Promise<void> => {
|
||
try {
|
||
let products: Product[] = []
|
||
const limit = targetLimit
|
||
|
||
console.log('加载热销商品,当前排序方式:', activeSort.value, 'limit:', limit)
|
||
|
||
switch (activeSort.value) {
|
||
case 'sales':
|
||
console.log('调用 getProductsBySales')
|
||
products = await supabaseService.getProductsBySales(limit)
|
||
break
|
||
case 'price':
|
||
console.log('调用 getProductsByPrice, 升序:', priceAscending.value)
|
||
products = await supabaseService.getProductsByPrice(limit, priceAscending.value)
|
||
break
|
||
case 'new':
|
||
console.log('调用 getProductsByNewest')
|
||
products = await supabaseService.getProductsByNewest(limit)
|
||
break
|
||
case 'recommend':
|
||
console.log('调用 getSmartRecommendations')
|
||
products = await supabaseService.getSmartRecommendations(limit)
|
||
break
|
||
case 'discount':
|
||
console.log('调用 getDiscountProducts')
|
||
products = await supabaseService.getDiscountProducts(limit)
|
||
break
|
||
default:
|
||
console.log('调用默认 getProductsBySales')
|
||
products = await supabaseService.getProductsBySales(limit)
|
||
}
|
||
|
||
console.log('加载到的商品数量:', products.length)
|
||
if (products.length > 0) {
|
||
console.log('Sample Product Merchant IDs:')
|
||
for (let i = 0; i < Math.min(products.length, 3); i++) {
|
||
const p = products[i]
|
||
console.log(` - Product: ${p.name}, MerchantID: ${p.merchant_id}`)
|
||
}
|
||
}
|
||
hotProducts.value = products
|
||
} catch (error) {
|
||
console.error('加载热销商品失败:', error)
|
||
hotProducts.value = []
|
||
}
|
||
}
|
||
|
||
// 获取热销商品(根据当前排序方式)
|
||
function loadHotProducts(targetLimit: number): Promise<void> {
|
||
return new Promise<void>((resolve, reject) => {
|
||
doLoadHotProducts(targetLimit, resolve, reject)
|
||
})
|
||
}
|
||
|
||
// 前置声明推荐商品加载函数
|
||
const doLoadRecommendedProducts = async (limit: number, resolve: (value: void) => void, reject: (reason?: any) => void): Promise<void> => {
|
||
recommendedProducts.value = await supabaseService.getRecommendedProducts(limit)
|
||
resolve()
|
||
}
|
||
|
||
// 获取推荐商品
|
||
function loadRecommendedProducts(limit: number): Promise<void> {
|
||
return new Promise<void>((resolve, reject) => {
|
||
doLoadRecommendedProducts(limit, resolve, reject)
|
||
})
|
||
}
|
||
|
||
// 加载热搜词
|
||
const loadHotKeywords = async (): Promise<void> => {
|
||
try {
|
||
const keywords = await supabaseService.getHotKeywords(10)
|
||
hotKeywords.value = keywords
|
||
console.log('加载热搜词:', keywords.length, '个')
|
||
} catch (error) {
|
||
console.error('加载热搜词失败:', error)
|
||
hotKeywords.value = []
|
||
}
|
||
}
|
||
|
||
// 点击热搜词进行搜索
|
||
const searchByKeyword = (keyword: string): void => {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/search?keyword=${encodeURIComponent(keyword)}`
|
||
})
|
||
}
|
||
|
||
// 初始化数据
|
||
const initData = async () => {
|
||
// 首先确保用户资料已加载
|
||
try {
|
||
await getCurrentUser()
|
||
console.log('主页初始化:用户资料加载完成')
|
||
} catch (error) {
|
||
console.error('加载用户资料失败:', error)
|
||
}
|
||
await loadCategories()
|
||
await loadBrands()
|
||
await loadHotKeywords()
|
||
await loadHotProducts(defaultLoadLimit)
|
||
await loadRecommendedProducts(defaultLoadLimit)
|
||
}
|
||
|
||
|
||
// 家庭常备药
|
||
const familyItems = [
|
||
{
|
||
id: 'family1',
|
||
name: '创可贴',
|
||
desc: '伤口护理',
|
||
icon: '🩹',
|
||
color: '#FF5722',
|
||
categoryId: 'external'
|
||
},
|
||
{
|
||
id: 'family2',
|
||
name: '体温计',
|
||
desc: '健康监测',
|
||
icon: '🌡️',
|
||
color: '#2196F3',
|
||
categoryId: 'device'
|
||
},
|
||
{
|
||
id: 'family3',
|
||
name: '消毒酒精',
|
||
desc: '环境消毒',
|
||
icon: '🧪',
|
||
color: '#4CAF50',
|
||
categoryId: 'external'
|
||
},
|
||
{
|
||
id: 'family4',
|
||
name: '口罩',
|
||
desc: '日常防护',
|
||
icon: '😷',
|
||
color: '#607D8B',
|
||
categoryId: 'device'
|
||
},
|
||
{
|
||
id: 'family5',
|
||
name: '退热贴',
|
||
desc: '物理降温',
|
||
icon: '🧊',
|
||
color: '#00BCD4',
|
||
categoryId: 'cold'
|
||
},
|
||
{
|
||
id: 'family6',
|
||
name: '棉签纱布',
|
||
desc: '伤口处理',
|
||
icon: '🩹',
|
||
color: '#FF9800',
|
||
categoryId: 'external'
|
||
}
|
||
]
|
||
|
||
// 初始化页面
|
||
const initPage = () => {
|
||
const systemInfo = uni.getSystemInfoSync()
|
||
statusBarHeight.value = systemInfo.statusBarHeight
|
||
|
||
// 计算滚动区域高度 - 不再需要手动计算,使用 Flex 布局自动撑开
|
||
// scrollHeight.value = windowHeight - 50
|
||
|
||
// 检测屏幕尺寸
|
||
const screenWidth = systemInfo.screenWidth
|
||
isMobile.value = screenWidth < 768 // 小于768px为小屏幕
|
||
}
|
||
|
||
// 生命周期
|
||
onMounted(() => {
|
||
initPage()
|
||
initData()
|
||
})
|
||
|
||
// 页面显示时重置状态
|
||
onShow(() => {
|
||
console.log('=== index页面onShow被调用 ===')
|
||
console.log('主页重新显示,重置页面状态')
|
||
|
||
// 重置导航栏显示状态
|
||
showNavbar.value = true
|
||
lastScrollTop.value = 0
|
||
|
||
// 重置滚动位置到顶部
|
||
// 注意:这里不能直接操作scroll-view的滚动位置
|
||
// 但可以重置一些页面状态
|
||
|
||
// 注意:这里不再清除selectedCategory
|
||
// 让分类页面在成功读取后自行清除
|
||
// 这样可以确保分类页面能正确读取到传递的数据
|
||
|
||
// 每次页面显示时尝试更新用户资料
|
||
if (!isFirstShow.value) {
|
||
getCurrentUser().then(profile => {
|
||
if (profile != null) {
|
||
console.log('主页onShow:用户资料更新成功')
|
||
} else {
|
||
console.log('主页onShow:用户资料为空,可能未登录')
|
||
}
|
||
}).catch(error => {
|
||
console.error('主页onShow:加载用户资料失败:', error)
|
||
})
|
||
} else {
|
||
isFirstShow.value = false
|
||
console.log('主页首次显示,跳过onShow中的用户资料检查,交由initData处理')
|
||
}
|
||
|
||
console.log('=== index页面onShow执行完成 ===')
|
||
})
|
||
|
||
// 处理滚动事件
|
||
const handleScroll = (event: any) => {
|
||
const eventObj = event as UTSJSONObject
|
||
const detail = eventObj.get('detail') as UTSJSONObject
|
||
const scrollTop = detail.getNumber('scrollTop') ?? 0
|
||
const currentTime = Date.now()
|
||
|
||
// 判断滚动方向
|
||
if (scrollTop > lastScrollTop.value) {
|
||
// 向下滚动
|
||
scrollingUp.value = false
|
||
// 向下滚动超过阈值时隐藏导航栏
|
||
if (scrollTop > scrollThreshold && showNavbar.value) {
|
||
showNavbar.value = false
|
||
}
|
||
} else if (scrollTop < lastScrollTop.value) {
|
||
// 向上滚动
|
||
scrollingUp.value = true
|
||
// 向上滚动时显示导航栏
|
||
if (!showNavbar.value) {
|
||
showNavbar.value = true
|
||
}
|
||
}
|
||
|
||
// 滚动到顶部时强制显示导航栏
|
||
if (scrollTop <= 10) {
|
||
showNavbar.value = true
|
||
}
|
||
|
||
lastScrollTop.value = scrollTop
|
||
|
||
// 调试信息(开发时可启用)
|
||
// console.log(`Scroll: ${scrollTop}, ShowNavbar: ${showNavbar.value}, ScrollingUp: ${scrollingUp.value}`)
|
||
}
|
||
|
||
// 重置导航栏显示状态(例如点击回到顶部时)
|
||
const resetNavbar = () => {
|
||
showNavbar.value = true
|
||
lastScrollTop.value = 0
|
||
}
|
||
|
||
// 切换分类 - 跳转到分类页面并传递分类ID
|
||
const switchCategory = (category: any) => {
|
||
console.log('=== switchCategory函数开始执行 ===')
|
||
|
||
// 将 category 转换为 UTSJSONObject 以访问属性
|
||
const catObj = (category instanceof UTSJSONObject) ? (category as UTSJSONObject) : (JSON.parse(JSON.stringify(category)) as UTSJSONObject)
|
||
const categoryId = catObj.getString('id') ?? ''
|
||
const categoryName = catObj.getString('name') ?? ''
|
||
|
||
console.log('分类ID:', categoryId, '分类名称:', categoryName)
|
||
|
||
// 使用Storage传递参数,确保switchTab后能被读取
|
||
uni.setStorageSync('selectedCategory', categoryId)
|
||
|
||
// 生成唯一的时间戳和随机参数,确保每次跳转都是新的页面
|
||
const timestamp = Date.now()
|
||
const randomParam = Math.random().toString(36).substring(2, 8)
|
||
|
||
// 构建带参数的URL,直接通过URL传递分类信息
|
||
const url = `/pages/mall/consumer/category?categoryId=${categoryId}&name=${encodeURIComponent(categoryName)}×tamp=${timestamp}&random=${randomParam}`
|
||
|
||
uni.switchTab({
|
||
url: '/pages/mall/consumer/category',
|
||
success: () => {
|
||
// 通过 Storage 传递参数已在上面设置
|
||
console.log('跳转分类页面成功,categoryId:', categoryId)
|
||
}
|
||
})
|
||
}
|
||
|
||
const switchBrand = (brand: Brand) => {
|
||
// 假设跳转到搜索结果页或者分类页带 filter
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/search?keyword=${encodeURIComponent(brand.name)}&type=brand&brandId=${brand.id}`
|
||
})
|
||
}
|
||
|
||
// 切换排序
|
||
const switchSort = (sortId: string) => {
|
||
// 如果点击的是价格排序,切换升序/降序
|
||
if (sortId === 'price' && activeSort.value === 'price') {
|
||
priceAscending.value = !priceAscending.value
|
||
console.log('切换价格排序方向,升序:', priceAscending.value)
|
||
} else {
|
||
// 切换到其他排序时,重置价格排序为升序
|
||
if (sortId !== 'price') {
|
||
priceAscending.value = true
|
||
}
|
||
activeSort.value = sortId
|
||
}
|
||
hasMore.value = true // 重置加载更多状态
|
||
// 重新加载热销商品,排序由 Supabase 服务处理
|
||
loadHotProducts(defaultLoadLimit)
|
||
}
|
||
|
||
// 切换筛选器
|
||
const switchFilter = (filterId: string) => {
|
||
activeFilter.value = filterId
|
||
// 重新加载推荐商品,筛选由 Supabase 服务处理
|
||
loadRecommendedProducts(defaultLoadLimit)
|
||
}
|
||
|
||
// 查看新闻详情
|
||
const viewNewsDetail = (news: any) => {
|
||
uni.navigateTo({
|
||
url: `/pages/news/detail?id=${news.id}`
|
||
})
|
||
}
|
||
|
||
// 下拉刷新
|
||
const onRefresh = async () => {
|
||
refreshing.value = true
|
||
|
||
try {
|
||
// 重新加载数据
|
||
await initData()
|
||
} catch (e) {
|
||
console.error('刷新数据失败:', e)
|
||
} finally {
|
||
// 延迟关闭刷新动画,确保用户能看到刷新过程
|
||
setTimeout(() => {
|
||
refreshing.value = false
|
||
// 延迟显示提示,避免与动画冲突
|
||
setTimeout(() => {
|
||
uni.showToast({
|
||
title: '刷新成功',
|
||
icon: 'success'
|
||
})
|
||
}, 200)
|
||
}, 800)
|
||
}
|
||
}
|
||
|
||
// 加载更多
|
||
const loadMore = async () => {
|
||
console.log('=== 触发触底事件 ===')
|
||
if (loading.value) {
|
||
console.log('正在加载中,跳过')
|
||
return
|
||
}
|
||
|
||
showLoadMore.value = true
|
||
loading.value = true
|
||
try {
|
||
// 获取当前热销商品的数量
|
||
const currentCount = hotProducts.value.length
|
||
const nextPage = Math.floor(currentCount / 6) + 1
|
||
const additionalLimit = 6
|
||
|
||
console.log('开始加载更多,当前数量:', currentCount, '页码:', nextPage)
|
||
|
||
// 加载更多商品
|
||
let newProducts: Product[] = []
|
||
switch (activeSort.value) {
|
||
case 'sales':
|
||
newProducts = await supabaseService.getProductsBySales(currentCount + additionalLimit)
|
||
break
|
||
case 'price':
|
||
newProducts = await supabaseService.getProductsByPrice(currentCount + additionalLimit, priceAscending.value)
|
||
break
|
||
case 'new':
|
||
newProducts = await supabaseService.getProductsByNewest(currentCount + additionalLimit)
|
||
break
|
||
case 'recommend':
|
||
newProducts = await supabaseService.getSmartRecommendations(currentCount + additionalLimit)
|
||
break
|
||
case 'discount':
|
||
newProducts = await supabaseService.getDiscountProducts(currentCount + additionalLimit)
|
||
break
|
||
default:
|
||
newProducts = await supabaseService.getProductsBySales(currentCount + additionalLimit)
|
||
}
|
||
|
||
console.log('加载到的新商品数量:', newProducts.length)
|
||
|
||
// 检查是否还有更多数据
|
||
if (newProducts.length <= currentCount) {
|
||
hasMore.value = false
|
||
uni.showToast({
|
||
title: '没有更多了',
|
||
icon: 'none'
|
||
})
|
||
} else {
|
||
// 更新商品列表
|
||
hotProducts.value = newProducts
|
||
}
|
||
} catch (error) {
|
||
console.error('加载更多失败:', error)
|
||
} finally {
|
||
loading.value = false
|
||
// 稍微延迟隐藏加载条,让用户看到
|
||
setTimeout(() => {
|
||
showLoadMore.value = false
|
||
}, 500)
|
||
}
|
||
}
|
||
|
||
// 添加到购物车
|
||
const addToCart = async (product: any) => {
|
||
uni.showLoading({ title: '检查商品...' })
|
||
try {
|
||
// 将 product 转换为 UTSJSONObject 以访问属性
|
||
const prodObj = (product instanceof UTSJSONObject) ? (product as UTSJSONObject) : (JSON.parse(JSON.stringify(product)) as UTSJSONObject)
|
||
const productId = prodObj.getString('id') ?? ''
|
||
const merchantId = prodObj.getString('merchant_id') ?? ''
|
||
|
||
// 检查商品是否有SKU
|
||
const skus = await supabaseService.getProductSkus(productId)
|
||
uni.hideLoading()
|
||
|
||
if (skus.length > 0) {
|
||
// 有规格,提示并跳转到商品详情页选择规格
|
||
uni.showToast({
|
||
title: '请选择规格',
|
||
icon: 'none'
|
||
})
|
||
setTimeout(() => {
|
||
uni.navigateTo({
|
||
url: '/pages/mall/consumer/product-detail?id=' + productId
|
||
})
|
||
}, 500)
|
||
} else {
|
||
// 无规格,直接加入购物车
|
||
uni.showLoading({ title: '添加中...' })
|
||
const success = await supabaseService.addToCart(productId, 1, '', merchantId)
|
||
uni.hideLoading()
|
||
if (success) {
|
||
uni.showToast({
|
||
title: '已添加到购物车',
|
||
icon: 'success'
|
||
})
|
||
} else {
|
||
uni.showToast({
|
||
title: '添加失败,请先登录',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
} catch (e) {
|
||
console.error('添加到购物车异常', e)
|
||
uni.hideLoading()
|
||
uni.showToast({
|
||
title: '操作异常',
|
||
icon: 'none'
|
||
})
|
||
}
|
||
}
|
||
|
||
// 扫码功能
|
||
const onScan = (): void => {
|
||
uni.scanCode({
|
||
success: (res) => {
|
||
console.log('扫码成功:', res)
|
||
uni.showToast({
|
||
title: '扫码成功: ' + res.result,
|
||
icon: 'none'
|
||
})
|
||
},
|
||
fail: (err) => {
|
||
console.error('扫码失败:', err)
|
||
}
|
||
})
|
||
}
|
||
|
||
// 相机功能
|
||
const onCamera = (): void => {
|
||
uni.chooseImage({
|
||
count: 1,
|
||
sourceType: ['camera'],
|
||
success: (res) => {
|
||
console.log('相机拍摄成功:', res.tempFilePaths[0])
|
||
uni.showToast({
|
||
title: '已拍摄,正在识别...',
|
||
icon: 'loading'
|
||
})
|
||
setTimeout(() => {
|
||
uni.showToast({
|
||
title: '识别成功',
|
||
icon: 'success'
|
||
})
|
||
}, 1000)
|
||
},
|
||
fail: (err) => {
|
||
console.error('相机调用失败:', err)
|
||
}
|
||
})
|
||
}
|
||
|
||
// 导航函数
|
||
const navigateToSearch = (): void => { uni.navigateTo({ url: '/pages/mall/consumer/search' }) }
|
||
const navigateToNews = (): void => { uni.navigateTo({ url: '/pages/news/list' }) }
|
||
const navigateToProduct = (product: any) => {
|
||
// 将 product 转换为 UTSJSONObject 以访问属性
|
||
const prodObj = (product instanceof UTSJSONObject) ? (product as UTSJSONObject) : (JSON.parse(JSON.stringify(product)) as UTSJSONObject)
|
||
|
||
// 使用productId(如果存在)作为跳转的商品ID,否则使用id
|
||
const productId = prodObj.getString('productId') ?? prodObj.getString('id') ?? ''
|
||
const name = prodObj.getString('name') ?? ''
|
||
// 使用 main_image_url
|
||
const image = prodObj.getString('main_image_url') ?? prodObj.getString('image') ?? '/static/product1.jpg'
|
||
const price = (prodObj.getNumber('base_price') ?? prodObj.getNumber('price') ?? 0).toString()
|
||
const marketPrice = prodObj.getNumber('market_price') ?? prodObj.getNumber('original_price') ?? (parseFloat(price) * 1.2)
|
||
const originalPrice = marketPrice.toString()
|
||
|
||
// 手动构建URL,避免双重编码问题
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/product-detail?id=${productId}&price=${price}&originalPrice=${originalPrice}&name=${encodeURIComponent(name)}&image=${encodeURIComponent(image)}`
|
||
})
|
||
}
|
||
const navigateToCategory = (item: any) => {
|
||
uni.navigateTo({
|
||
url: `/pages/mall/consumer/search?keyword=${encodeURIComponent(item.name)}&type=family`
|
||
})
|
||
}
|
||
const navigateToConsultation = () => uni.navigateTo({ url: '/pages/medicine/consultation' })
|
||
const navigateToPrescription = () => uni.navigateTo({ url: '/pages/medicine/prescription' })
|
||
const navigateToOTC = () => uni.navigateTo({ url: '/pages/medicine/otc' })
|
||
const navigateToHealthTools = () => uni.navigateTo({ url: '/pages/medicine/tools' })
|
||
const navigateToReminders = () => uni.navigateTo({ url: '/pages/user/reminders' })
|
||
</script>
|
||
|
||
<style>
|
||
/* 全局重置 removed - uniapp-x does not support * selector */
|
||
/* .medic-home * {
|
||
box-sizing: border-box;
|
||
margin: 0;
|
||
padding: 0;
|
||
} */
|
||
|
||
.medic-home {
|
||
width: 100%;
|
||
height: 100%;
|
||
overflow: hidden;
|
||
background: #f8fafc;
|
||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', sans-serif;
|
||
line-height: 1.5;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.main-scroll {
|
||
flex: 1;
|
||
height: 1px; /* 让 flex 生效并允许滚动 */
|
||
width: 100%;
|
||
}
|
||
|
||
/* 智能导航栏 - 重新设计布局 */
|
||
.smart-navbar {
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
background-color: #4CAF50;
|
||
z-index: 1000;
|
||
box-shadow: 0 2px 12px rgba(76, 175, 80, 0.15);
|
||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
|
||
/* 导航栏搜索框容器内边距调整 */
|
||
.search-container {
|
||
height: 44px;
|
||
padding: 0 16px;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
max-width: 1400px;
|
||
margin: 0 auto;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 搜索框 hover 效果 */
|
||
.search-box:hover {
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
/* 导航栏搜索框容器内边距调整 */
|
||
.search-box {
|
||
flex: 1;
|
||
max-width: 600px;
|
||
background: #f0f0f0;
|
||
border-radius: 20px;
|
||
padding: 0 4px 0 12px;
|
||
display: flex;
|
||
flex-direction: row; /* UVUE 显式设置 row */
|
||
align-items: center;
|
||
/* cursor: pointer; removed for uniapp-x support */
|
||
transition: all 0.3s ease;
|
||
width: 100%;
|
||
height: 32px; /* 减小高度,与顶部高度44px适配,略小于顶部高度 */
|
||
}
|
||
|
||
.search-placeholder {
|
||
font-size: 14px;
|
||
color: #999;
|
||
flex: 1;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.nav-icon-btn {
|
||
padding: 4px 8px 4px 4px;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-right: 1px solid #ddd;
|
||
margin-right: 8px;
|
||
}
|
||
|
||
.nav-icon {
|
||
font-size: 18px;
|
||
}
|
||
|
||
/* 搜索按钮高度微调 */
|
||
.nav-inner-search-btn {
|
||
padding: 0 12px; /* 减小内边距 */
|
||
background-color: #87CEEB; /* 天空蓝 */
|
||
border-radius: 16px;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
height: 24px; /* 随搜索框高度减小而减小 */
|
||
}
|
||
|
||
.nav-inner-search-text {
|
||
font-size: 12px; /* 字体稍微变小 */
|
||
color: #ffffff;
|
||
font-weight: normal;
|
||
}
|
||
|
||
/* 导航栏占位符 */
|
||
.navbar-placeholder {
|
||
width: 100%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.nav-camera-btn {
|
||
padding: 4px 8px 4px 4px;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border-right-width: 1px;
|
||
border-right-style: solid;
|
||
border-right-color: #ddd;
|
||
border-right: 1px solid #ddd; /* 修复UVUE样式 */
|
||
margin-right: 8px;
|
||
}
|
||
|
||
.nav-camera-icon {
|
||
font-size: 20px;
|
||
}
|
||
|
||
/* 主内容区域 */
|
||
.main-scroll {
|
||
flex: 1;
|
||
padding: 0 16px 16px;
|
||
max-width: 1400px;
|
||
margin-left: auto;
|
||
margin-right: auto;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 智能健康卡片 */
|
||
.smart-health-card {
|
||
background: linear-gradient(135deg, #2196F3 0%, #1976D2 100%);
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
/* margin-top 由 style 动态控制 */
|
||
color: white;
|
||
}
|
||
|
||
.health-content {
|
||
display: flex;
|
||
flex-direction: column;
|
||
/* gap: 12px; removed for uniapp-x support */
|
||
}
|
||
|
||
.health-header {
|
||
display: flex;
|
||
flex-direction: column;
|
||
/* gap: 4px; removed for uniapp-x support */
|
||
margin-bottom: 12px; /* acts as gap for health-content */
|
||
}
|
||
|
||
.health-title {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
margin-bottom: 4px; /* acts as gap for health-header */
|
||
}
|
||
|
||
.health-subtitle {
|
||
font-size: 14px;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.health-tips {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
/* gap: 12px; removed for uniapp-x support */
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.tip-item {
|
||
font-size: 13px;
|
||
padding: 6px 12px;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
border-radius: 20px;
|
||
/* backdrop-filter: blur(10px); removed for uniapp-x support */
|
||
margin-right: 12px;
|
||
margin-bottom: 12px; /* acts as gap for health-tips */
|
||
}
|
||
|
||
/* 智能分类网格 */
|
||
.smart-categories {
|
||
background: white;
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.section-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: flex-start;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.category-tabs-pills {
|
||
display: flex;
|
||
flex-direction: row;
|
||
background-color: #f0f2f5;
|
||
padding: 3px;
|
||
border-radius: 20px;
|
||
align-items: center;
|
||
}
|
||
|
||
.tab-pill {
|
||
padding: 6px 18px;
|
||
border-radius: 17px;
|
||
transition: all 0.3s;
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.tab-pill.active {
|
||
background-color: #fff;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.08);
|
||
}
|
||
|
||
.tab-text {
|
||
font-size: 14px;
|
||
color: #888;
|
||
font-weight: normal;
|
||
}
|
||
|
||
.tab-pill.active .tab-text {
|
||
color: #4CAF50;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
color: #666;
|
||
transition: color 0.3s;
|
||
}
|
||
|
||
.section-title.active {
|
||
color: #4CAF50;
|
||
font-size: 20px;
|
||
}
|
||
|
||
.section-desc {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
/* 分类网格布局 */
|
||
.category-grid {
|
||
display: flex;
|
||
flex-direction: row; /* Ensure items are in row */
|
||
flex-wrap: wrap;
|
||
/* gap: 16px; removed for uniapp-x support */
|
||
margin: 0 -1.5%;
|
||
}
|
||
|
||
.category-card {
|
||
width: 18%; /* 一行5个 */
|
||
margin: 0 1% 12px 1%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 10px;
|
||
background: #f8f9fa;
|
||
border-radius: 10px;
|
||
/* cursor: pointer; removed for uniapp-x support */
|
||
transition: all 0.3s ease;
|
||
border: 1px solid transparent;
|
||
position: relative;
|
||
}
|
||
|
||
.category-card:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
border-color: var(--card-color, #4CAF50);
|
||
}
|
||
|
||
/* 二级分类样式 */
|
||
.sub-category-grid {
|
||
background: #f8f9fa;
|
||
border-radius: 12px;
|
||
padding: 16px;
|
||
margin-top: 16px;
|
||
}
|
||
|
||
.sub-category-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
padding-bottom: 8px;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
}
|
||
|
||
.sub-category-title {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.sub-category-close {
|
||
font-size: 16px;
|
||
color: #999;
|
||
padding: 4px 8px;
|
||
}
|
||
|
||
.sub-category-wrapper {
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.sub-category-card {
|
||
width: 23%;
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 10px 4px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: 1px solid #eee;
|
||
margin-right: 2%;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.sub-category-card .card-icon {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 18px;
|
||
margin-bottom: 6px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.sub-category-card .card-icon-text {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.sub-category-card .card-name {
|
||
font-size: 11px;
|
||
color: #333;
|
||
text-align: center;
|
||
lines: 1;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
.card-icon {
|
||
width: 44px;
|
||
height: 44px;
|
||
border-radius: 22px;
|
||
background: var(--card-color, #4CAF50);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.card-icon-text {
|
||
font-size: 20px;
|
||
color: white;
|
||
}
|
||
|
||
.card-name {
|
||
font-size: 12px;
|
||
font-weight: normal;
|
||
color: #333;
|
||
margin-bottom: 4px;
|
||
text-align: center;
|
||
width: 100%;
|
||
}
|
||
|
||
.card-desc {
|
||
font-size: 12px;
|
||
color: #666;
|
||
text-align: center;
|
||
}
|
||
|
||
/* 二级分类样式 */
|
||
.sub-category-grid {
|
||
background: #f8f9fa;
|
||
border-radius: 12px;
|
||
padding: 16px;
|
||
margin-top: 16px;
|
||
}
|
||
|
||
.sub-category-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 12px;
|
||
padding-bottom: 8px;
|
||
border-bottom: 1px solid #e0e0e0;
|
||
}
|
||
|
||
.sub-category-title {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.sub-category-close {
|
||
font-size: 16px;
|
||
color: #999;
|
||
padding: 4px 8px;
|
||
}
|
||
|
||
.sub-category-wrapper {
|
||
display: flex;
|
||
flex-direction: row;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.sub-category-card {
|
||
width: 23%;
|
||
background: white;
|
||
border-radius: 8px;
|
||
padding: 10px 4px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
border: 1px solid #eee;
|
||
margin-right: 2%;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.sub-category-card .card-icon {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 18px;
|
||
margin-bottom: 6px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.sub-category-card .card-icon-text {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.sub-category-card .card-name {
|
||
font-size: 11px;
|
||
color: #333;
|
||
text-align: center;
|
||
lines: 1;
|
||
text-overflow: ellipsis;
|
||
}
|
||
|
||
/* 健康资讯 */
|
||
.health-news {
|
||
background: white;
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.news-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: 16px;
|
||
}
|
||
|
||
.news-title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.news-more {
|
||
font-size: 14px;
|
||
color: #4CAF50;
|
||
/* cursor: pointer; removed for uvue support */
|
||
}
|
||
|
||
.news-swiper {
|
||
height: 200px;
|
||
border-radius: 12px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.news-content {
|
||
position: relative;
|
||
height: 100%;
|
||
border-radius: 12px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.news-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: flex;
|
||
}
|
||
|
||
.news-caption {
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
line-height: 1.4;
|
||
display: flex;
|
||
}
|
||
|
||
/* 智能服务 */
|
||
.smart-services {
|
||
background: white;
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.services-grid {
|
||
display: flex;
|
||
flex-direction: row; /* Ensure items are in row */
|
||
flex-wrap: wrap;
|
||
/* gap: 20px; removed for uniapp-x support */
|
||
margin: 0 -1.5%;
|
||
}
|
||
|
||
.service-card {
|
||
width: 47%; /* 50 - 3 */
|
||
margin: 0 1.5% 20px 1.5%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 20px;
|
||
background: #f8f9fa;
|
||
border-radius: 12px;
|
||
/* cursor: pointer; removed for uvue support */
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.service-card:hover {
|
||
transform: translateY(-4px);
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.service-icon {
|
||
width: 60px;
|
||
height: 60px;
|
||
border-radius: 30px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.service-icon-text {
|
||
font-size: 28px;
|
||
color: white;
|
||
}
|
||
|
||
.service-name {
|
||
font-size: 15px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.service-desc {
|
||
font-size: 12px;
|
||
color: #666;
|
||
}
|
||
|
||
/* 热搜词区域 */
|
||
.hot-keywords-section {
|
||
background: white;
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
}
|
||
|
||
.keywords-list {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
margin-top: 15px;
|
||
}
|
||
|
||
.keyword-item {
|
||
display: flex;
|
||
align-items: center;
|
||
padding: 8px 16px;
|
||
background: #f5f5f5;
|
||
border-radius: 20px;
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.keyword-item:hover {
|
||
background: #fff0f0;
|
||
}
|
||
|
||
.keyword-rank {
|
||
width: 20px;
|
||
height: 20px;
|
||
border-radius: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 12px;
|
||
font-weight: bold;
|
||
color: #999;
|
||
background: #eee;
|
||
margin-right: 8px;
|
||
}
|
||
|
||
.keyword-rank.top-three {
|
||
background: #ff4757;
|
||
color: white;
|
||
}
|
||
|
||
.keyword-text {
|
||
font-size: 14px;
|
||
color: #333;
|
||
}
|
||
|
||
/* 热销药品 */
|
||
.hot-products {
|
||
background: white;
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.section-header {
|
||
display: flex;
|
||
flex-direction: column; /* 标题和筛选器垂直排列 */
|
||
align-items: flex-start;
|
||
margin-bottom: 20px;
|
||
width: 100%;
|
||
}
|
||
|
||
.title-section {
|
||
display: flex;
|
||
align-items: center;
|
||
/* gap: 8px; removed */
|
||
width: 100%;
|
||
}
|
||
|
||
.section-icon {
|
||
font-size: 20px;
|
||
color: #4CAF50;
|
||
margin-right: 8px; /* Replacement for gap */
|
||
}
|
||
|
||
.sort-tabs {
|
||
display: flex;
|
||
flex-direction: row; /* UVUE 显式设置 row */
|
||
/* gap: 8px; removed */
|
||
align-items: center;
|
||
flex-wrap: wrap; /* 允许换行,实现自适应 */
|
||
justify-content: flex-start;
|
||
width: 100%;
|
||
margin-top: 12px;
|
||
}
|
||
|
||
.sort-tab {
|
||
font-size: 13px;
|
||
color: #666;
|
||
padding: 8px 12px; /* 增加左右内边距 */
|
||
border-radius: 20px;
|
||
border: 1px solid #e0e0e0;
|
||
/* cursor: pointer; removed for uvue support */
|
||
transition: all 0.2s ease;
|
||
white-space: nowrap;
|
||
flex: 1; /* 均分宽度 */
|
||
min-width: 70px; /* 设置最小宽度防止过窄 */
|
||
text-align: center;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin-right: 8px; /* Replacement for gap */
|
||
}
|
||
|
||
.sort-tab.active {
|
||
background: #4CAF50;
|
||
color: white;
|
||
border-color: #4CAF50;
|
||
}
|
||
|
||
.sort-tab:hover {
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.sort-tab.active:hover {
|
||
background: #388E3C;
|
||
}
|
||
|
||
/* 产品网格 */
|
||
.products-grid {
|
||
display: flex; /* 替换 block 为 flex */
|
||
flex-direction: row; /* 确保横向排列 */
|
||
flex-wrap: wrap; /* 确保网格布局 */
|
||
/* gap: 10px; removed for uniapp-x support */
|
||
justify-content: space-between; /* use space-between instead of gap */
|
||
margin-top: 20px;
|
||
min-height: 500px; /* 确保有足够高度触发滚动 */
|
||
padding-bottom: 20px;
|
||
}
|
||
|
||
.product-card {
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: #fff;
|
||
border-radius: 8px;
|
||
overflow: hidden;
|
||
width: 48%;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.product-image {
|
||
width: 100%;
|
||
height: 170px;
|
||
border-radius: 8px;
|
||
margin-bottom: 8px;
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.product-name {
|
||
font-size: 13px;
|
||
color: #333;
|
||
margin-bottom: 5px;
|
||
line-height: 1.4;
|
||
height: 36px;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
padding: 0 8px;
|
||
}
|
||
|
||
.product-bottom {
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
padding: 0 8px 8px;
|
||
}
|
||
|
||
.product-price {
|
||
font-size: 15px;
|
||
color: #ff5000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.product-add-btn {
|
||
width: 24px;
|
||
height: 24px;
|
||
background-color: #ff5000;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.add-icon {
|
||
color: #fff;
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.cart-btn {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
/* gap: 6px; removed */
|
||
background: #4CAF50;
|
||
color: white;
|
||
padding: 8px 12px;
|
||
border-radius: 8px;
|
||
font-size: 13px;
|
||
font-weight: bold;
|
||
/* cursor: pointer; removed for uvue support */
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.cart-btn:hover {
|
||
background: #388E3C;
|
||
}
|
||
|
||
.cart-icon {
|
||
font-size: 14px;
|
||
margin-right: 6px; /* Replacement for gap */
|
||
}
|
||
|
||
.cart-text {
|
||
font-size: 13px;
|
||
}
|
||
|
||
/* 家庭常备药 */
|
||
.family-medicine {
|
||
background: white;
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.section-subtitle {
|
||
font-size: 14px;
|
||
color: #666;
|
||
margin-left: 12px;
|
||
}
|
||
|
||
.family-grid {
|
||
display: flex;
|
||
flex-direction: row; /* Ensure items are in row */
|
||
flex-wrap: wrap;
|
||
/* gap: 16px; removed for uniapp-x support */
|
||
margin: 0 -1.5%;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.family-item {
|
||
width: 47%; /* 50 - 3 */
|
||
margin: 0 1.5% 16px 1.5%;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 16px;
|
||
background: #f8f9fa;
|
||
border-radius: 12px;
|
||
/* cursor: pointer; removed for uvue support */
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.family-item:hover {
|
||
transform: translateY(-2px);
|
||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||
}
|
||
|
||
.family-icon {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: 24px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.family-icon-text {
|
||
font-size: 20px;
|
||
color: white;
|
||
}
|
||
|
||
.family-name {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.family-desc {
|
||
font-size: 12px;
|
||
color: #666;
|
||
}
|
||
|
||
/* 智能推荐 */
|
||
.smart-recommend {
|
||
background: white;
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
margin-bottom: 20px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.recommend-filters {
|
||
display: flex;
|
||
flex-direction: row; /* UVUE 显式设置 row */
|
||
/* gap: 8px; removed for uniapp-x support */
|
||
align-items: center;
|
||
flex-wrap: wrap; /* 允许换行,实现自适应 */
|
||
justify-content: flex-start;
|
||
width: 100%;
|
||
margin-top: 12px;
|
||
}
|
||
|
||
.filter-item {
|
||
font-size: 13px;
|
||
color: #666;
|
||
padding: 8px 12px; /* 增加左右内边距 */
|
||
border-radius: 20px;
|
||
border: 1px solid #e0e0e0;
|
||
/* cursor: pointer; removed for uvue support */
|
||
transition: all 0.2s ease;
|
||
white-space: nowrap;
|
||
flex: 1; /* 均分宽度 */
|
||
min-width: 80px; /* 设置最小宽度防止过窄 */
|
||
text-align: center;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
margin-right: 8px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.filter-item.active {
|
||
background: #4CAF50;
|
||
color: white;
|
||
border-color: #4CAF50;
|
||
}
|
||
|
||
.filter-item:hover {
|
||
background: #f5f5f5;
|
||
}
|
||
|
||
.filter-item.active:hover {
|
||
background: #388E3C;
|
||
}
|
||
|
||
.recommend-grid {
|
||
display: flex;
|
||
flex-direction: row; /* Ensure items are in row */
|
||
flex-wrap: wrap;
|
||
/* gap: 20px; removed for uniapp-x support */
|
||
margin: 0 -1.5%;
|
||
margin-top: 20px;
|
||
}
|
||
|
||
.recommend-product {
|
||
width: 97%; /* 1 col */
|
||
margin: 0 1.5% 20px 1.5%;
|
||
background: #f8f9fa;
|
||
border-radius: 12px;
|
||
overflow: hidden;
|
||
/* cursor: pointer; removed for uvue support */
|
||
transition: all 0.3s ease;
|
||
border: 1px solid #e0e0e0;
|
||
}
|
||
|
||
.recommend-product:hover {
|
||
transform: translateY(-4px);
|
||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
|
||
}
|
||
|
||
.product-image-container {
|
||
position: relative;
|
||
height: 180px;
|
||
}
|
||
|
||
.product-image-container .product-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
background: white;
|
||
}
|
||
|
||
.product-tags {
|
||
position: absolute;
|
||
top: 12px;
|
||
left: 12px;
|
||
display: flex;
|
||
flex-direction: row;
|
||
/* gap: 8px; removed */
|
||
}
|
||
|
||
.product-tag, .featured-tag {
|
||
padding: 4px 10px;
|
||
border-radius: 10px;
|
||
font-size: 11px;
|
||
font-weight: bold;
|
||
color: white;
|
||
margin-right: 8px;
|
||
}
|
||
|
||
.product-tag {
|
||
background: rgba(76, 175, 80, 0.9);
|
||
}
|
||
|
||
.featured-tag {
|
||
background: rgba(255, 87, 34, 0.9);
|
||
}
|
||
|
||
.product-details {
|
||
padding: 16px;
|
||
}
|
||
|
||
.product-title {
|
||
font-size: 16px;
|
||
font-weight: bold;
|
||
color: #333;
|
||
margin-bottom: 4px;
|
||
line-height: 1.4;
|
||
display: flex;
|
||
}
|
||
|
||
.product-specification {
|
||
font-size: 13px;
|
||
color: #666;
|
||
margin-bottom: 12px;
|
||
display: flex;
|
||
}
|
||
|
||
.product-rating {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
/* gap: 8px; removed */
|
||
margin-bottom: 12px;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.rating-stars {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
/* gap: 4px; removed */
|
||
margin-right: 8px;
|
||
}
|
||
|
||
.star-icon {
|
||
font-size: 14px;
|
||
color: #FFC107;
|
||
margin-right: 2px;
|
||
}
|
||
|
||
.rating-value {
|
||
font-weight: bold;
|
||
color: #333;
|
||
}
|
||
|
||
.reviews-count {
|
||
color: #666;
|
||
}
|
||
|
||
.product-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
margin-top: 12px;
|
||
}
|
||
|
||
.add-to-cart {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 18px;
|
||
background: #4CAF50;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
/* cursor: pointer; removed for uvue support */
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.add-to-cart:hover {
|
||
background: #388E3C;
|
||
transform: scale(1.1);
|
||
}
|
||
|
||
.cart-icon {
|
||
font-size: 16px;
|
||
color: white;
|
||
}
|
||
|
||
/* 健康提醒 */
|
||
.health-reminder {
|
||
background: linear-gradient(135deg, #FF9800 0%, #F57C00 100%);
|
||
border-radius: 16px;
|
||
padding: 16px 20px;
|
||
margin-bottom: 20px;
|
||
color: white;
|
||
}
|
||
|
||
.reminder-content {
|
||
display: flex;
|
||
flex-direction: row;
|
||
align-items: center;
|
||
/* gap: 12px; removed */
|
||
}
|
||
|
||
.reminder-icon {
|
||
font-size: 24px;
|
||
margin-right: 12px;
|
||
}
|
||
|
||
.reminder-text {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
/* gap: 4px; removed */
|
||
}
|
||
|
||
.reminder-title {
|
||
font-size: 15px;
|
||
font-weight: bold;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.reminder-desc {
|
||
font-size: 13px;
|
||
opacity: 0.9;
|
||
}
|
||
|
||
.reminder-action {
|
||
padding: 6px 16px;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
border-radius: 20px;
|
||
/* cursor: pointer; removed for uvue support */
|
||
transition: all 0.2s ease;
|
||
}
|
||
|
||
.reminder-action:hover {
|
||
background: rgba(255, 255, 255, 0.3);
|
||
}
|
||
|
||
.action-text {
|
||
font-size: 13px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 加载状态 */
|
||
.loading-state {
|
||
padding: 40px 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 32px;
|
||
height: 32px;
|
||
border: 3px solid #f0f0f0;
|
||
border-top-color: #4CAF50;
|
||
border-radius: 16px;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.loading-text {
|
||
font-size: 14px;
|
||
color: #666;
|
||
}
|
||
|
||
.no-more {
|
||
padding: 30px 0;
|
||
text-align: center;
|
||
border-top: 1px solid #f0f0f0;
|
||
margin-top: 10px;
|
||
}
|
||
|
||
.no-more-text {
|
||
font-size: 13px;
|
||
color: #999;
|
||
}
|
||
|
||
/* 安全区域 */
|
||
.safe-area {
|
||
height: 20px;
|
||
width: 100%;
|
||
}
|
||
|
||
/* ===== 响应式设计 ===== */
|
||
|
||
/* 小屏手机 (小于414px) */
|
||
@media screen and (max-width: 414px) {
|
||
.search-container {
|
||
padding: 0 12px;
|
||
height: 44px;
|
||
}
|
||
|
||
.search-box {
|
||
padding: 0 4px 0 12px;
|
||
margin: 0;
|
||
}
|
||
|
||
.main-scroll {
|
||
padding: 0 12px 12px;
|
||
}
|
||
|
||
.category-grid {
|
||
margin: 0 -1%;
|
||
padding: 0 4px;
|
||
}
|
||
|
||
.category-grid .category-card {
|
||
width: 18%;
|
||
margin: 0 1% 6px 1%;
|
||
padding: 4px 0;
|
||
background: transparent;
|
||
box-shadow: none;
|
||
border: none;
|
||
}
|
||
|
||
.category-card:hover {
|
||
transform: none;
|
||
box-shadow: none;
|
||
}
|
||
|
||
.card-icon {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 18px;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.card-icon-text {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.card-name {
|
||
font-size: 10px;
|
||
font-weight: normal;
|
||
color: #333;
|
||
}
|
||
|
||
.card-desc {
|
||
display: none;
|
||
}
|
||
|
||
.services-grid .service-card {
|
||
width: 23%; /* 4 cols */
|
||
margin: 0 1% 8px 1%;
|
||
}
|
||
|
||
.service-card {
|
||
padding: 10px 4px;
|
||
background: #f8f9fa; /* 保持淡色背景 */
|
||
}
|
||
|
||
.service-icon {
|
||
width: 40px;
|
||
height: 40px;
|
||
border-radius: 20px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.service-icon-text {
|
||
font-size: 20px;
|
||
}
|
||
|
||
.service-name {
|
||
font-size: 11px;
|
||
}
|
||
|
||
.service-desc {
|
||
display: none; /* 隐藏描述 */
|
||
}
|
||
|
||
.load-more-status {
|
||
padding: 20px;
|
||
display: flex;
|
||
justify-content: center;
|
||
align-items: center;
|
||
width: 100%;
|
||
}
|
||
|
||
.loading-text {
|
||
color: #888;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.products-grid {
|
||
/* column-count: 2; removed for flex */
|
||
/* column-gap: 8px; removed */
|
||
}
|
||
|
||
.recommend-grid .recommend-product {
|
||
width: 48%;
|
||
margin: 0 1% 8px 1%;
|
||
}
|
||
|
||
.product-info,
|
||
.product-details {
|
||
padding: 6px; /* 极小内边距 */
|
||
}
|
||
|
||
.product-name,
|
||
.product-title {
|
||
font-size: 13px; /* 调整字体大小 */
|
||
height: 36px; /* 限制高度,防止参差不齐 */
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
/* display: webkit-box removed for compatibility */
|
||
display: flex;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.product-image,
|
||
.product-image-container {
|
||
height: 140px; /* 稍微减小图片高度适配双列 */
|
||
}
|
||
|
||
/* 手机端商品卡片极简模式(热销 & 推荐) */
|
||
.hot-products .product-spec,
|
||
.hot-products .manufacturer,
|
||
.hot-products .original-price,
|
||
.hot-products .cart-text,
|
||
.hot-products .sales-info,
|
||
.hot-products .product-action, /* 隐藏热销区加购按钮 */
|
||
.smart-recommend .product-specification,
|
||
.smart-recommend .product-rating,
|
||
.smart-recommend .original-price,
|
||
.smart-recommend .product-actions /* 隐藏推荐区加购按钮 */
|
||
{
|
||
display: none;
|
||
}
|
||
|
||
.hot-products .product-info,
|
||
.smart-recommend .product-details {
|
||
padding: 6px; /* 极小内边距 */
|
||
}
|
||
|
||
.hot-products .product-image,
|
||
.hot-products .product-image-container,
|
||
.smart-recommend .product-image,
|
||
.smart-recommend .product-image-container {
|
||
height: 110px; /* 进一步减小图片高度 */
|
||
}
|
||
|
||
.hot-products .product-name,
|
||
.smart-recommend .product-title {
|
||
margin-bottom: 2px;
|
||
font-size: 12px;
|
||
line-height: 1.3;
|
||
height: 32px; /* 限制2行高度 */
|
||
}
|
||
|
||
.hot-products .price-section,
|
||
.smart-recommend .price-section {
|
||
margin-bottom: 0;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
.hot-products .price-symbol,
|
||
.smart-recommend .price-symbol {
|
||
font-size: 10px;
|
||
color: #FF5722;
|
||
}
|
||
|
||
.hot-products .price-value,
|
||
.smart-recommend .price-value {
|
||
font-size: 14px; /* 字体变小 */
|
||
font-weight: bold;
|
||
}
|
||
|
||
.family-grid .family-item {
|
||
width: 23%; /* 4 cols */
|
||
margin: 0 1% 8px 1%;
|
||
padding: 8px 4px;
|
||
background: #f8f9fa;
|
||
}
|
||
|
||
|
||
|
||
.family-icon {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 18px;
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
.family-icon-text {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.family-name {
|
||
font-size: 11px;
|
||
}
|
||
|
||
.family-desc {
|
||
display: none;
|
||
}
|
||
|
||
.news-swiper {
|
||
height: 160px;
|
||
}
|
||
|
||
.sort-tabs,
|
||
.recommend-filters {
|
||
/* gap: 8px; removed */
|
||
justify-content: flex-start; /* 保持左对齐 */
|
||
/* overflow-x: auto; REMOVED for uniapp-x support - use generic view wrapping instead */
|
||
/* flex-wrap: nowrap; REMOVED to allow wrapping on mobile since overflow-x not supported on view */
|
||
padding-bottom: 4px; /* 滚动条空间 */
|
||
}
|
||
|
||
.sort-tab,
|
||
.filter-item {
|
||
padding: 5px 12px;
|
||
font-size: 12px;
|
||
flex-shrink: 0; /* 防止被压缩 */
|
||
min-width: 0; /* CHANGED from auto to 0 */
|
||
flex: 0 0 auto; /* 取消均分 */
|
||
margin-right: 8px;
|
||
margin-bottom: 8px; /* Added spacing for wrapped items */
|
||
}
|
||
|
||
.section-header {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
/* gap: 12px; removed */
|
||
}
|
||
|
||
.title-section {
|
||
justify-content: center;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.sort-tabs,
|
||
.recommend-filters {
|
||
width: 100%;
|
||
justify-content: center;
|
||
}
|
||
}
|
||
|
||
/* 中屏手机/小平板 (415px-768px) */
|
||
@media screen and (min-width: 415px) and (max-width: 768px) {
|
||
.search-container {
|
||
padding: 0 16px;
|
||
height: 44px;
|
||
}
|
||
|
||
.main-scroll {
|
||
/* 移除 margin-top */
|
||
}
|
||
|
||
.category-grid .category-card {
|
||
width: 30.33%;
|
||
}
|
||
|
||
.services-grid .service-card {
|
||
width: 47%;
|
||
}
|
||
|
||
.products-grid {
|
||
/* column-count: 2; removed */
|
||
}
|
||
|
||
.recommend-grid .recommend-product {
|
||
width: 47%;
|
||
}
|
||
|
||
.family-grid .family-item {
|
||
width: 30.33%;
|
||
}
|
||
|
||
.sort-tabs,
|
||
.recommend-filters {
|
||
/* gap: 10px; removed */
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.sort-tab,
|
||
.filter-item {
|
||
padding: 6px 14px;
|
||
font-size: 12px;
|
||
flex-grow: 0;
|
||
margin-right: 10px;
|
||
}
|
||
|
||
.section-header {
|
||
flex-direction: column;
|
||
align-items: stretch;
|
||
/* gap: 12px; removed */
|
||
}
|
||
|
||
.title-section {
|
||
justify-content: center;
|
||
margin-bottom: 12px;
|
||
}
|
||
|
||
.sort-tabs,
|
||
.recommend-filters {
|
||
width: 100%;
|
||
justify-content: center;
|
||
}
|
||
}
|
||
|
||
/* 平板设备 (769px-1024px) */
|
||
@media screen and (min-width: 769px) and (max-width: 1024px) {
|
||
.search-container {
|
||
padding: 0 24px;
|
||
height: 44px;
|
||
}
|
||
|
||
.nav-search-tools .nav-tool-item {
|
||
display: none;
|
||
}
|
||
|
||
.main-scroll {
|
||
padding: 0 24px 20px;
|
||
}
|
||
|
||
.category-grid .category-card {
|
||
width: 22%;
|
||
}
|
||
|
||
.services-grid .service-card {
|
||
width: 22%;
|
||
}
|
||
|
||
.product-card {
|
||
/* width: calc((100% - 20px) / 3); */
|
||
width: 32%; /* Fallback for calc */
|
||
/* margin-right: 1.33%; */
|
||
}
|
||
|
||
.recommend-grid .recommend-product {
|
||
width: 47%;
|
||
}
|
||
|
||
.family-grid .family-item {
|
||
width: 30.33%;
|
||
}
|
||
|
||
.news-swiper {
|
||
height: 240px;
|
||
}
|
||
}
|
||
|
||
/* 桌面端 (1025px以上) */
|
||
@media screen and (min-width: 1025px) {
|
||
.search-container {
|
||
padding: 0 32px;
|
||
height: 44px;
|
||
}
|
||
|
||
.main-scroll {
|
||
padding: 0 32px 24px;
|
||
}
|
||
|
||
.category-grid .category-card {
|
||
width: 13.66%;
|
||
}
|
||
|
||
.services-grid .service-card {
|
||
width: 22%;
|
||
}
|
||
|
||
.product-card {
|
||
/* width: calc((100% - 30px) / 4); */
|
||
width: 23%;
|
||
/* margin-right: 2%; */
|
||
}
|
||
|
||
.recommend-grid .recommend-product {
|
||
width: 30.33%;
|
||
}
|
||
|
||
.family-grid .family-item {
|
||
width: 30.33%;
|
||
}
|
||
|
||
.news-swiper {
|
||
height: 260px;
|
||
}
|
||
}
|
||
|
||
/* 大桌面端 (1400px以上) */
|
||
@media screen and (min-width: 1400px) {
|
||
.category-grid {
|
||
margin-right: -24px;
|
||
}
|
||
.category-grid .category-card {
|
||
width: 17%;
|
||
margin: 0 1.5% 24px 1.5%;
|
||
}
|
||
|
||
.product-card {
|
||
/* width: calc((100% - 30px) / 4); */
|
||
width: 23%;
|
||
/* margin-right: 2%; */
|
||
}
|
||
|
||
.recommend-grid .recommend-product {
|
||
width: 22%;
|
||
}
|
||
}
|
||
|
||
/* 暗黑模式适配 */
|
||
@media (prefers-color-scheme: dark) {
|
||
.medic-home {
|
||
background: #121212;
|
||
}
|
||
|
||
.smart-categories,
|
||
.health-news,
|
||
.smart-services,
|
||
.hot-products,
|
||
.family-medicine,
|
||
.smart-recommend {
|
||
background: #1e1e1e;
|
||
border-color: #333;
|
||
}
|
||
|
||
.nav-search-box {
|
||
background: rgba(30, 30, 30, 0.95);
|
||
border-color: #444;
|
||
}
|
||
|
||
.category-card,
|
||
.service-card,
|
||
.product-card,
|
||
.family-item,
|
||
.recommend-product {
|
||
background: #2d2d2d;
|
||
border-color: #444;
|
||
}
|
||
|
||
.section-title,
|
||
.card-name,
|
||
.service-name,
|
||
.product-name,
|
||
.family-name,
|
||
.product-title,
|
||
.section-desc,
|
||
.card-desc,
|
||
.service-desc,
|
||
.product-spec,
|
||
.product-specification,
|
||
.family-desc {
|
||
color: #aaa;
|
||
}
|
||
|
||
.sort-tab,
|
||
.filter-item {
|
||
background: #333;
|
||
border-color: #444;
|
||
color: #ccc;
|
||
}
|
||
|
||
.sort-tab.active,
|
||
.filter-item.active {
|
||
background: #4CAF50;
|
||
color: white;
|
||
}
|
||
|
||
.sort-tab:hover,
|
||
.filter-item:hover {
|
||
background: #444;
|
||
}
|
||
|
||
.sort-tab.active:hover,
|
||
.filter-item.active:hover {
|
||
background: #388E3C;
|
||
}
|
||
|
||
.nav-tool-item {
|
||
background: rgba(76, 175, 80, 0.2);
|
||
color: #4CAF50;
|
||
}
|
||
|
||
.manufacturer,
|
||
.sales-count,
|
||
.reviews-count,
|
||
.original-price {
|
||
color: #888;
|
||
}
|
||
}
|
||
</style>
|
||
|