Files
medical-mall/pages/mall/consumer/index.uvue

2254 lines
47 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!-- 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="onScan">
<text class="nav-icon">🔳</text>
</view>
<!-- 相机图标 -->
<view class="nav-camera-btn" @click="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
scroll-y
class="main-scroll"
refresher-enabled
:refresher-triggered="refreshing"
:lower-threshold="50"
@refresherrefresh="onRefresh"
@scrolltolower="loadMore"
@scroll="handleScroll"
>
<!-- 健康资讯轮播 (Moved Up) -->
<view class="health-news">
<view class="news-header">
<text class="news-title">健康资讯</text>
<text class="news-more" @click="navigateToNews">更多 ></text>
</view>
<swiper
class="news-swiper"
:autoplay="true"
:interval="4000"
:duration="500"
:circular="true"
:indicator-dots="true"
indicator-color="rgba(255,255,255,0.3)"
indicator-active-color="#4CAF50"
>
<swiper-item
v-for="news in healthNews"
:key="news.id"
class="news-item"
>
<view class="news-content" @click="viewNewsDetail(news)">
<image
class="news-image"
:src="news.image"
mode="aspectFill"
/>
<view class="news-overlay">
<text class="news-tag">{{ news.tag }}</text>
<text class="news-caption">{{ news.title }}</text>
</view>
</view>
</swiper-item>
</swiper>
</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">
<view class="section-header">
<text class="section-title">智能分类</text>
<text class="section-desc">快速定位所需药品</text>
</view>
<view class="category-grid">
<view
v-for="category in categories"
:key="category.id"
class="category-card"
@click="switchCategory(category)"
:style="{ '--card-color': category.color }"
>
<view class="card-icon">
<text>{{ category.icon }}</text>
</view>
<text class="card-name">{{ category.name }}</text>
<text class="card-desc">{{ category.desc }}</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>👨‍⚕️</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>📋</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>💊</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>🩺</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)"
>
<view class="product-badge" v-if="product.is_hot">热销</view>
<image
class="product-image"
:src="product.main_image_url"
mode="aspectFill"
/>
<view class="product-info">
<text class="product-name">{{ product.name }}</text>
<!-- spec is omitted if not available -->
<view class="price-section">
<view class="current-price">
<text class="price-symbol">¥</text>
<text class="price-value">{{ product.base_price }}</text>
</view>
<text class="original-price" v-if="product.market_price != null && product.market_price! > product.base_price">
¥{{ product.market_price }}
</text>
</view>
<view class="product-meta">
<text class="manufacturer">{{ product.brand_name || product.shop_name || '自营' }}</text>
<view class="sales-info">
<text class="sales-count">已售{{ product.sale_count }}</text>
</view>
</view>
<view class="product-action">
<view class="cart-btn" @click="addToCart(product)">
<text class="cart-icon">+</text>
<text class="cart-text">加入购物车</text>
</view>
</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>{{ 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 } from '@dcloudio/uni-app'
import supabaseService from '@/utils/supabaseService.uts'
import type { Product, Category } 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 hotProducts = ref<Product[]>([])
const recommendedProducts = ref<Product[]>([])
// 屏幕尺寸检测
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 categories = ref<Category[]>([])
// 排序标签
const sortTabs = [
{ 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 () => {
try {
const categoriesData = await supabaseService.getCategories()
// 映射字段根据ml_categories表结构映射
categories.value = categoriesData.map((cat: any) => ({
id: cat.id,
name: cat.name,
icon: cat.icon_url || '📦', // 使用icon_url字段
desc: cat.description || '', // 使用description字段
color: '#4CAF50' // 默认颜色表中可能没有color字段
}))
} 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 (targetLimit: number = 6) => {
try {
let products: Product[] = []
const limit = targetLimit
console.log('加载热销商品,当前排序方式:', activeSort.value, 'limit:', limit)
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 = async () => {
// 首先确保用户资料已加载
try {
await getCurrentUser()
console.log('主页初始化:用户资料加载完成')
} catch (error) {
console.error('加载用户资料失败:', error)
}
await loadCategories()
await loadHotProducts()
await loadRecommendedProducts()
}
// 家庭常备药
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'
}
]
// 生命周期
onMounted(async () => {
initPage()
await 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) {
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 initPage = () => {
const systemInfo = uni.getSystemInfoSync()
statusBarHeight.value = systemInfo.statusBarHeight || 0
// 计算滚动区域高度 - 不再需要手动计算,使用 Flex 布局自动撑开
// scrollHeight.value = windowHeight - 50
// 检测屏幕尺寸
const screenWidth = systemInfo.screenWidth || systemInfo.windowWidth
isMobile.value = screenWidth < 768 // 小于768px为小屏幕
}
// 处理滚动事件
const handleScroll = (event: any) => {
const scrollTop = event.detail.scrollTop
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函数开始执行 ===')
console.log('分类ID:', category.id, '分类名称:', category.name)
// 清除可能存在的旧数据
uni.removeStorageSync('selectedCategory')
// 生成唯一的时间戳和随机参数,确保每次跳转都是新的页面
const timestamp = Date.now()
const randomParam = Math.random().toString(36).substring(2, 8)
// 构建带参数的URL直接通过URL传递分类信息
const url = `/pages/mall/consumer/category?categoryId=${category.id}&name=${encodeURIComponent(category.name)}&timestamp=${timestamp}&random=${randomParam}`
console.log('跳转URL:', url)
console.log('分类ID参数:', category.id)
console.log('时间戳:', timestamp)
console.log('随机参数:', randomParam)
// 使用uni.reLaunch跳转到分类页面关闭所有页面并打开新页面
// 这样可以确保每次跳转都是全新的页面实例,避免页面缓存问题
// 虽然这会关闭当前主页,但可以确保分类页面总是重新加载
uni.reLaunch({
url: url,
success: () => {
console.log('✅ 使用reLaunch跳转到分类页面成功')
console.log('=== switchCategory函数执行完成 ===')
},
fail: (err) => {
console.error('❌ 跳转到分类页面失败:', err)
console.log('=== switchCategory函数执行完成 ===')
}
})
}
// 切换排序
const switchSort = (sortId: string) => {
activeSort.value = sortId
hasMore.value = true // 重置加载更多状态
// 重新加载热销商品,排序由 Supabase 服务处理
loadHotProducts()
}
// 切换筛选器
const switchFilter = (filterId: string) => {
activeFilter.value = filterId
// 重新加载推荐商品,筛选由 Supabase 服务处理
loadRecommendedProducts()
}
// 查看新闻详情
const viewNewsDetail = (news: any) => {
uni.navigateTo({
url: `/pages/news/detail?id=${news.id}`
})
}
// 下拉刷新
const onRefresh = () => {
refreshing.value = true
setTimeout(() => {
refreshing.value = false
uni.showToast({
title: '刷新成功',
icon: 'success'
})
}, 1500)
}
// 加载更多
const loadMore = async () => {
console.log('=== 触发触底事件 ===')
if (loading.value) {
console.log('正在加载中,跳过')
return
}
showLoadMore.value = true
loading.value = true
try {
// 获取当前热销商品的数量
const currentCount = hotProducts.value.length
const nextLimit = currentCount + 6
console.log('开始加载更多,当前数量:', currentCount, '目标数量:', nextLimit)
// 加载更多热销商品
await loadHotProducts(nextLimit)
// 检查是否还有更多数据
if (hotProducts.value.length === currentCount) {
hasMore.value = false
uni.showToast({
title: '没有更多了',
icon: 'none'
})
} else {
// 还有数据,或者是刚加载了一批
/* uni.showToast({
title: '加载完成',
icon: 'success'
}) */
}
} catch (error) {
console.error('加载更多失败:', error)
} finally {
loading.value = false
// 稍微延迟隐藏加载条,让用户看到
setTimeout(() => {
showLoadMore.value = false
}, 500)
}
}
// 添加到购物车
const addToCart = async (product: any, e: any | null = null) => {
e?.stopPropagation()
uni.showLoading({ title: '添加中...' })
try {
// 尝试调用 Supabase 服务添加
const success = await supabaseService.addToCart(product.id, 1)
if (success) {
uni.showToast({
title: '已添加到购物车',
icon: 'success'
})
} else {
// 失败(如未登录),回退到本地存储或提示登录
// 这里简单提示失败
uni.showToast({
title: '添加失败,请先登录',
icon: 'none'
})
}
} catch (e) {
console.error('添加到购物车异常', e)
uni.showToast({
title: '操作异常',
icon: 'none'
})
} finally {
uni.hideLoading()
}
}
// 导航函数
const navigateToSearch = () => uni.navigateTo({ url: '/pages/mall/consumer/search' })
const navigateToNews = () => uni.navigateTo({ url: '/pages/news/list' })
const navigateToProduct = (product: any) => {
// 使用productId如果存在作为跳转的商品ID否则使用id
const productId = product.productId || product.id
const name = product.name || ''
// 使用 main_image_url
const image = product.main_image_url || product.image || '/static/product1.jpg'
const price = (product.base_price || product.price || 0).toString()
const originalPrice = (product.market_price || product.original_price || (parseFloat(price) * 1.2).toFixed(2))?.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' })
// 扫码功能
const onScan = (e: any | null) => {
e?.stopPropagation()
uni.scanCode({
success: (res) => {
console.log('扫码结果:' + res.result)
uni.showToast({
title: '扫码成功',
icon: 'success'
})
// 这里可以添加基于扫码结果的逻辑,比如跳转到商品详情
},
fail: (err) => {
console.error('扫码失败:', err)
}
})
}
// 相机功能e: any | null) => {
e?.stopPropagation()
const onCamera = () => {
uni.chooseImage({
count: 1,
sourceType: ['camera'],
success: (res) => {
console.log('拍照结果:', res.tempFilePaths)
uni.showToast({
title: '拍摄成功',
icon: 'success'
})
// 这里可以添加基于图片的逻辑,比如图搜
},
fail: (err) => {
console.error('拍照失败:', err)
}
})
}
</script>
<style>
/* 全局重置 */
.medic-home * {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.medic-home {
width: 100%;
height: 100vh;
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: linear-gradient(135deg, #4CAF50 0%, #2E7D32 100%);
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);
will-change: transform, opacity;
pointer-events: auto; /* 确保导航栏可以交互 */
backface-visibility: hidden; /* 改善动画性能 */
-webkit-backface-visibility: hidden;
}
/* 导航栏搜索框容器内边距调整 */
.search-container {
height: 44px; /* 调整为与消息页一致的高度 */
padding: 0 16px;
display: flex;
flex-direction: row; /* 显式设置 flex-direction: row */
align-items: center;
justify-content: space-between;
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;
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: 500;
}
/* 导航栏占位符 */
.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%;
overflow-y: auto;
-webkit-overflow-scrolling: touch; /* 改善iOS滚动体验 */
}
/* 智能健康卡片 */
.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;
}
.health-header {
display: flex;
flex-direction: column;
gap: 4px;
}
.health-title {
font-size: 20px;
font-weight: bold;
}
.health-subtitle {
font-size: 14px;
opacity: 0.9;
}
.health-tips {
display: flex;
flex-wrap: wrap;
gap: 12px;
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);
}
/* 智能分类网格 */
.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;
}
.section-title {
font-size: 18px;
font-weight: bold;
color: #333;
}
.section-desc {
font-size: 14px;
color: #666;
}
/* 分类网格布局 */
.category-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 16px;
}
.category-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 16px;
background: #f8f9fa;
border-radius: 12px;
cursor: pointer;
transition: all 0.3s ease;
border: 1px solid transparent;
}
.category-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
border-color: var(--card-color, #4CAF50);
}
.card-icon {
width: 56px;
height: 56px;
border-radius: 28px;
background: var(--card-color, #4CAF50);
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 12px;
}
.card-icon text {
font-size: 24px;
color: white;
}
.card-name {
font-size: 15px;
font-weight: 600;
color: #333;
margin-bottom: 4px;
text-align: center;
}
.card-desc {
font-size: 12px;
color: #666;
text-align: center;
}
/* 健康资讯 */
.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;
}
.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: block;
}
.news-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(to top, rgba(0, 0, 0, 0.8), transparent);
padding: 20px;
color: white;
}
.news-tag {
display: inline-block;
background: #4CAF50;
padding: 4px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
margin-bottom: 8px;
}
.news-caption {
font-size: 16px;
font-weight: 600;
display: block;
line-height: 1.4;
}
/* 智能服务 */
.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: grid;
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
gap: 20px;
}
.service-card {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
background: #f8f9fa;
border-radius: 12px;
cursor: pointer;
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: 600;
color: #333;
margin-bottom: 4px;
}
.service-desc {
font-size: 12px;
color: #666;
}
/* 热销药品 */
.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;
width: 100%;
}
.section-icon {
font-size: 20px;
color: #4CAF50;
}
.sort-tabs {
display: flex;
flex-direction: row; /* UVUE 显式设置 row */
gap: 8px;
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;
transition: all 0.2s ease;
white-space: nowrap;
flex: 1; /* 均分宽度 */
min-width: 70px; /* 设置最小宽度防止过窄 */
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}
.sort-tab.active {
background: #4CAF50;
color: white;
border-color: #4CAF50;
}
.sort-tab:hover {
background: #f5f5f5;
}
.sort-tab.active:hover {
background: #388E3C;
}
/* 产品网格 */
.products-grid {
display: block;
column-count: 2;
column-gap: 10px;
margin-top: 20px;
min-height: 500px; /* 确保有足够高度触发滚动 */
padding-bottom: 20px;
}
.product-card {
break-inside: avoid;
margin-bottom: 10px;
background: #f8f9fa;
border-radius: 12px;
overflow: hidden;
cursor: pointer;
transition: all 0.3s ease;
border: 1px solid #e0e0e0;
position: relative;
}
.product-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.product-badge {
position: absolute;
top: 12px;
left: 12px;
background: #FF5722;
color: white;
font-size: 11px;
padding: 4px 12px;
border-radius: 12px;
font-weight: 600;
z-index: 2;
}
.product-image {
width: 100%;
height: 160px;
object-fit: cover;
background: white;
}
.product-info {
padding: 16px;
}
.product-name {
font-size: 15px;
font-weight: 600;
color: #333;
margin-bottom: 4px;
display: block;
line-height: 1.4;
}
.product-spec {
font-size: 13px;
color: #666;
margin-bottom: 12px;
display: block;
}
.price-section {
display: flex;
align-items: baseline;
gap: 8px;
margin-bottom: 12px;
}
.current-price {
display: flex;
align-items: baseline;
}
.price-symbol {
font-size: 14px;
color: #FF5722;
}
.price-value {
font-size: 20px;
font-weight: bold;
color: #FF5722;
margin-left: 2px;
}
.original-price {
font-size: 13px;
color: #999;
text-decoration: line-through;
}
.product-meta {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
margin-bottom: 12px;
}
.manufacturer {
color: #666;
}
.sales-count {
color: #999;
}
.product-action {
margin-top: 12px;
}
.cart-btn {
display: flex;
align-items: center;
justify-content: center;
gap: 6px;
background: #4CAF50;
color: white;
padding: 8px 12px;
border-radius: 8px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
}
.cart-btn:hover {
background: #388E3C;
}
.cart-icon {
font-size: 14px;
}
.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: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 16px;
margin-top: 20px;
}
.family-item {
display: flex;
flex-direction: column;
align-items: center;
padding: 16px;
background: #f8f9fa;
border-radius: 12px;
cursor: pointer;
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: 600;
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;
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;
transition: all 0.2s ease;
white-space: nowrap;
flex: 1; /* 均分宽度 */
min-width: 80px; /* 设置最小宽度防止过窄 */
text-align: center;
display: flex;
justify-content: center;
align-items: center;
}
.filter-item.active {
background: #4CAF50;
color: white;
border-color: #4CAF50;
}
.filter-item:hover {
background: #f5f5f5;
}
.filter-item.active:hover {
background: #388E3C;
}
.recommend-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 20px;
margin-top: 20px;
}
.recommend-product {
background: #f8f9fa;
border-radius: 12px;
overflow: hidden;
cursor: pointer;
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 {
width: 100%;
height: 100%;
object-fit: cover;
background: white;
}
.product-tags {
position: absolute;
top: 12px;
left: 12px;
display: flex;
gap: 8px;
}
.product-tag, .featured-tag {
padding: 4px 10px;
border-radius: 10px;
font-size: 11px;
font-weight: 600;
color: white;
}
.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: 600;
color: #333;
margin-bottom: 4px;
display: block;
line-height: 1.4;
}
.product-specification {
font-size: 13px;
color: #666;
margin-bottom: 12px;
display: block;
}
.product-rating {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 12px;
font-size: 13px;
}
.rating-stars {
display: flex;
align-items: center;
gap: 4px;
}
.star-icon {
font-size: 14px;
color: #FFC107;
}
.rating-value {
font-weight: 600;
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;
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;
align-items: center;
gap: 12px;
}
.reminder-icon {
font-size: 24px;
}
.reminder-text {
flex: 1;
display: flex;
flex-direction: column;
gap: 4px;
}
.reminder-title {
font-size: 15px;
font-weight: 600;
}
.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;
transition: all 0.2s ease;
}
.reminder-action:hover {
background: rgba(255, 255, 255, 0.3);
}
.action-text {
font-size: 13px;
font-weight: 500;
}
/* 加载状态 */
.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: 50%;
animation: spin 1s linear infinite;
margin-bottom: 12px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.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; /* 恢复为44px与PC和分类页逻辑保持一致 */
}
.search-box {
padding: 8px 16px; /* 与分类页保持一致 */
max-width: 100%;
margin: 0;
}
.main-scroll {
padding: 0 12px 12px;
}
.category-grid {
grid-template-columns: repeat(5, 1fr); /* 调整为一行5个正好两行 */
gap: 8px;
padding: 0 4px;
}
.category-card {
padding: 8px 0;
background: transparent; /* 移除卡片背景 */
box-shadow: none; /* 移除阴影 */
border: none; /* 移除边框 */
}
.category-card:hover {
transform: none; /* 移动端移除悬停效果 */
box-shadow: none;
}
.card-icon {
width: 44px; /* 减小图标尺寸 */
height: 44px;
border-radius: 22px;
margin-bottom: 6px;
}
.card-icon text {
font-size: 20px;
}
.card-name {
font-size: 11px; /* 减小文字大小 */
font-weight: normal;
color: #333;
}
.card-desc {
display: none; /* 手机端隐藏描述文字,保持界面整洁 */
}
.services-grid {
grid-template-columns: repeat(4, 1fr); /* 服务入口也调整为一行4个 */
gap: 8px;
}
.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,
.recommend-grid {
grid-template-columns: repeat(2, 1fr); /* 手机端调整为双列显示 */
gap: 8px; /* 减小间距 */
}
.product-info,
.product-details {
padding: 8px; /* 减小内边距 */
}
.product-name,
.product-title {
font-size: 13px; /* 调整字体大小 */
height: 36px; /* 限制高度,防止参差不齐 */
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
.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: 600;
}
.family-grid {
grid-template-columns: repeat(4, 1fr); /* 家庭常备药也调整为一行4个 */
gap: 8px;
}
.family-item {
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;
justify-content: flex-start; /* 保持左对齐 */
overflow-x: auto; /* 允许横向滚动 */
flex-wrap: nowrap; /* 禁止换行 */
padding-bottom: 4px; /* 滚动条空间 */
}
.sort-tab,
.filter-item {
padding: 5px 12px;
font-size: 12px;
flex-shrink: 0; /* 防止被压缩 */
min-width: auto;
flex: 0 0 auto; /* 取消均分 */
}
.section-header {
flex-direction: column;
align-items: stretch;
gap: 12px;
}
.title-section {
justify-content: center;
}
.sort-tabs,
.recommend-filters {
width: 100%;
}
}
/* 中屏手机/小平板 (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 {
grid-template-columns: repeat(3, 1fr);
}
.services-grid {
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.products-grid {
column-count: 2;
}
.recommend-grid {
grid-template-columns: repeat(2, 1fr);
}
.family-grid {
grid-template-columns: repeat(3, 1fr);
}
.sort-tabs,
.recommend-filters {
gap: 10px;
justify-content: flex-start;
}
.sort-tab,
.filter-item {
padding: 6px 14px;
font-size: 12px;
flex-grow: 0;
}
.section-header {
flex-direction: column;
align-items: stretch;
gap: 12px;
}
.title-section {
justify-content: center;
}
.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;
max-width: 100%;
height: 44px;
}
.nav-search-tools .nav-tool-item {
display: none;
}
.main-scroll {
max-width: 100%;
padding: 0 24px 20px;
}
.category-grid {
grid-template-columns: repeat(4, 1fr);
}
.services-grid {
grid-template-columns: repeat(4, 1fr);
}
.products-grid {
column-count: 3;
}
.recommend-grid {
grid-template-columns: repeat(2, 1fr);
}
.family-grid {
grid-template-columns: repeat(3, 1fr);
}
.news-swiper {
height: 240px;
}
}
/* 桌面端 (1025px以上) */
@media screen and (min-width: 1025px) {
.search-container {
padding: 0 32px;
height: 44px;
}
.main-scroll {
max-width: 100%;
padding: 0 32px 24px;
}
.category-grid {
grid-template-columns: repeat(6, 1fr);
}
.services-grid {
grid-template-columns: repeat(4, 1fr);
}
.products-grid {
column-count: 4;
}
.recommend-grid {
grid-template-columns: repeat(3, 1fr);
}
.family-grid {
grid-template-columns: repeat(3, 1fr);
}
.news-swiper {
height: 260px;
}
}
/* 大桌面端 (1400px以上) */
@media screen and (min-width: 1400px) {
.category-grid {
grid-template-columns: repeat(5, 1fr);
gap: 24px;
}
.products-grid {
column-count: 4;
}
.recommend-grid {
grid-template-columns: repeat(4, 1fr);
}
}
/* 暗黑模式适配 */
@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>