1540 lines
31 KiB
Plaintext
1540 lines
31 KiB
Plaintext
<!-- pages/mall/consumer/index.uvue -->
|
||
<template>
|
||
<view class="consumer-home">
|
||
<!-- 自定义顶部导航栏(简化版) -->
|
||
<view class="custom-navbar" :style="{ paddingTop: statusBarHeight + 'px' }">
|
||
<view class="nav-content">
|
||
<view class="location" @click="showCityPicker">
|
||
<text class="location-icon">📍</text>
|
||
<text class="location-text">{{ currentCity }}</text>
|
||
<text class="location-arrow">▼</text>
|
||
</view>
|
||
|
||
<view class="nav-icons">
|
||
<view class="icon-item" @click="navigateToMessages">
|
||
<text class="icon">💬</text>
|
||
<text v-if="unreadMessageCount > 0" class="message-badge">{{ unreadMessageCount }}</text>
|
||
</view>
|
||
<view class="icon-item" @click="navigateToCart">
|
||
<text class="icon">🛒</text>
|
||
<text v-if="cartCount > 0" class="cart-badge">{{ cartCount }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 主内容区 -->
|
||
<scroll-view
|
||
scroll-y
|
||
class="main-content"
|
||
:style="{ height: scrollViewHeight + 'px' }"
|
||
refresher-enabled
|
||
:refresher-triggered="refreshing"
|
||
@refresherrefresh="onRefresh"
|
||
@scrolltolower="loadMore"
|
||
:show-scrollbar="false"
|
||
>
|
||
<!-- 商品分类区域 - 修复横向滚动 -->
|
||
<view class="category-section">
|
||
<scroll-view
|
||
scroll-x
|
||
class="category-scroll"
|
||
:show-scrollbar="false"
|
||
:scroll-left="scrollLeft"
|
||
@scroll="onScroll"
|
||
>
|
||
<view class="category-container">
|
||
<view
|
||
v-for="(category, index) in categoryList"
|
||
:key="category.id"
|
||
:class="['category-item', { active: activeCategory === category.id }]"
|
||
@click="switchCategory(category.id, index)"
|
||
>
|
||
<view class="category-icon-wrapper">
|
||
<text class="category-icon">{{ category.icon }}</text>
|
||
</view>
|
||
<text class="category-name">{{ category.name }}</text>
|
||
</view>
|
||
</view>
|
||
</scroll-view>
|
||
</view>
|
||
|
||
<!-- 搜索栏 -->
|
||
<view class="search-section" @click="navigateToSearch">
|
||
<view class="search-container">
|
||
<view class="search-box">
|
||
<text class="search-icon">🔍</text>
|
||
<text class="search-placeholder">搜索商品/品牌/店铺</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 轮播图 -->
|
||
<view class="banner-section">
|
||
<swiper
|
||
class="banner-swiper"
|
||
:autoplay="true"
|
||
:interval="4000"
|
||
:duration="500"
|
||
:circular="true"
|
||
:indicator-dots="true"
|
||
indicator-color="rgba(255,255,255,0.6)"
|
||
indicator-active-color="#ff5000"
|
||
>
|
||
<swiper-item v-for="(banner, index) in bannerList" :key="banner.id">
|
||
<image
|
||
class="banner-image"
|
||
:src="banner.image_url"
|
||
mode="aspectFill"
|
||
/>
|
||
</swiper-item>
|
||
</swiper>
|
||
</view>
|
||
|
||
<!-- 快捷入口 -->
|
||
<view class="quick-actions">
|
||
<view class="action-item" @click="navigateToFlashSale">
|
||
<view class="action-icon flash">⚡</view>
|
||
<text class="action-text">限时秒杀</text>
|
||
</view>
|
||
<view class="action-item" @click="navigateToCoupons">
|
||
<view class="action-icon coupon">🎫</view>
|
||
<text class="action-text">领券中心</text>
|
||
</view>
|
||
<view class="action-item" @click="navigateToDailyDeals">
|
||
<view class="action-icon daily">🔥</view>
|
||
<text class="action-text">每日特价</text>
|
||
</view>
|
||
<view class="action-item" @click="navigateToBrand">
|
||
<view class="action-icon brand">🏷️</view>
|
||
<text class="action-text">品牌特卖</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 限时秒杀 -->
|
||
<view class="flash-sale-section">
|
||
<view class="section-header">
|
||
|
||
</view>
|
||
|
||
<!-- 限时秒杀商品网格 -->
|
||
<view class="flash-grid">
|
||
<view
|
||
v-for="(product, index) in flashSaleProducts"
|
||
:key="index"
|
||
class="flash-product"
|
||
@click="navigateToProduct(product)"
|
||
>
|
||
<view class="product-image-wrapper">
|
||
<image
|
||
class="product-image"
|
||
:src="product.image"
|
||
mode="aspectFill"
|
||
/>
|
||
<view v-if="product.tag" class="product-tag">{{ product.tag }}</view>
|
||
</view>
|
||
<view class="price-info">
|
||
<text class="flash-price">¥{{ product.price }}</text>
|
||
<text class="original-price">¥{{ product.original_price }}</text>
|
||
<view class="progress-container">
|
||
<view class="progress-bar">
|
||
<view class="progress-inner" :style="{ width: product.soldPercent + '%' }"></view>
|
||
</view>
|
||
<text class="sold-text">已抢{{ product.soldPercent }}%</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 为你推荐 - 瀑布流布局 -->
|
||
<view class="recommend-section">
|
||
<view class="section-header">
|
||
<view class="title-with-icon">
|
||
<text class="recommend-icon">❤️</text>
|
||
<text class="section-title">为你推荐</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 瀑布流容器 -->
|
||
<view class="waterfall-container">
|
||
<!-- 左列 -->
|
||
<view class="waterfall-column left-column">
|
||
<view
|
||
v-for="(product, index) in leftColumnProducts"
|
||
:key="product.id"
|
||
class="product-card"
|
||
@click="navigateToProduct(product)"
|
||
>
|
||
<view class="product-image-wrapper">
|
||
<image
|
||
class="product-image"
|
||
:src="product.image"
|
||
mode="widthFix"
|
||
lazy-load="true"
|
||
/>
|
||
<view v-if="product.tag" class="product-tag">{{ product.tag }}</view>
|
||
</view>
|
||
<view class="product-info">
|
||
<text class="product-title">{{ product.name }}</text>
|
||
<view class="price-section">
|
||
<view class="current-price">
|
||
<text class="price-symbol">¥</text>
|
||
<text class="price-value">{{ product.price }}</text>
|
||
</view>
|
||
<text v-if="product.original_price > product.price" class="original-price">
|
||
¥{{ product.original_price }}
|
||
</text>
|
||
</view>
|
||
<view class="product-meta">
|
||
<text class="sales-count">{{ product.sales }}人已买</text>
|
||
<view class="shop-info" v-if="product.shop">
|
||
<text class="shop-name">{{ product.shop }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 右列 -->
|
||
<view class="waterfall-column right-column">
|
||
<view
|
||
v-for="(product, index) in rightColumnProducts"
|
||
:key="product.id"
|
||
class="product-card"
|
||
@click="navigateToProduct(product)"
|
||
>
|
||
<view class="product-image-wrapper">
|
||
<image
|
||
class="product-image"
|
||
:src="product.image"
|
||
mode="widthFix"
|
||
lazy-load="true"
|
||
/>
|
||
<view v-if="product.tag" class="product-tag">{{ product.tag }}</view>
|
||
</view>
|
||
<view class="product-info">
|
||
<text class="product-title">{{ product.name }}</text>
|
||
<view class="price-section">
|
||
<view class="current-price">
|
||
<text class="price-symbol">¥</text>
|
||
<text class="price-value">{{ product.price }}</text>
|
||
</view>
|
||
<text v-if="product.original_price > product.price" class="original-price">
|
||
¥{{ product.original_price }}
|
||
</text>
|
||
</view>
|
||
<view class="product-meta">
|
||
<text class="sales-count">{{ product.sales }}人已买</text>
|
||
<view class="shop-info" v-if="product.shop">
|
||
<text class="shop-name">{{ product.shop }}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 加载状态 -->
|
||
<view v-if="loading" class="loading-container">
|
||
<view class="loading-spinner"></view>
|
||
<text class="loading-text">加载中...</text>
|
||
</view>
|
||
|
||
<view v-if="!hasMore && productList.length > 0" class="no-more">
|
||
<text>--- 我是有底线的 ---</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 底部安全区域 -->
|
||
<view class="safe-area"></view>
|
||
</scroll-view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup lang="uts">
|
||
import { ref, reactive, onMounted, onUnmounted, computed } from 'vue'
|
||
|
||
// 响应式数据
|
||
const bannerList = ref<any[]>([])
|
||
const categoryList = ref<any[]>([])
|
||
const productList = ref<any[]>([])
|
||
const flashSaleProducts = ref<any[]>([])
|
||
const currentCity = ref<string>('北京市')
|
||
const refreshing = ref<boolean>(false)
|
||
const loading = ref<boolean>(false)
|
||
const hasMore = ref<boolean>(true)
|
||
const page = ref<number>(1)
|
||
const activeCategory = ref<string>('1')
|
||
const activeSort = ref<string>('recommend')
|
||
const statusBarHeight = ref<number>(0)
|
||
const scrollViewHeight = ref<number>(0)
|
||
const scrollLeft = ref<number>(0)
|
||
const cartCount = ref<number>(0)
|
||
const unreadMessageCount = ref<number>(3)
|
||
|
||
// 倒计时数据
|
||
const countdown = reactive({
|
||
hours: '02',
|
||
minutes: '30',
|
||
seconds: '15'
|
||
})
|
||
|
||
// 排序选项
|
||
const sortOptions = [
|
||
{ id: 'recommend', name: '推荐' },
|
||
{ id: 'new', name: '新品' },
|
||
{ id: 'hot', name: '热销' },
|
||
{ id: 'priceAsc', name: '价格↑' },
|
||
{ id: 'priceDesc', name: '价格↓' }
|
||
]
|
||
|
||
// 计算瀑布流列数据
|
||
const leftColumnProducts = computed(() => {
|
||
return productList.value.filter((_, index) => index % 2 === 0)
|
||
})
|
||
|
||
const rightColumnProducts = computed(() => {
|
||
return productList.value.filter((_, index) => index % 2 === 1)
|
||
})
|
||
|
||
// Mock 数据
|
||
const mockData = {
|
||
banners: [
|
||
{
|
||
id: '1',
|
||
title: '双11狂欢购',
|
||
image_url: 'https://picsum.photos/750/350?random=1'
|
||
},
|
||
{
|
||
id: '2',
|
||
title: '品牌品质日',
|
||
image_url: 'https://picsum.photos/750/350?random=2'
|
||
},
|
||
{
|
||
id: '3',
|
||
title: '新人专享礼',
|
||
image_url: 'https://picsum.photos/750/350?random=3'
|
||
}
|
||
],
|
||
|
||
categories: [
|
||
{ id: '1', name: '推荐', icon: '⭐' },
|
||
{ id: '2', name: '女装', icon: '👗' },
|
||
{ id: '3', name: '男装', icon: '👔' },
|
||
{ id: '4', name: '鞋靴', icon: '👠' },
|
||
{ id: '5', name: '箱包', icon: '👜' },
|
||
{ id: '6', name: '美妆', icon: '💄' },
|
||
{ id: '7', name: '数码', icon: '📱' },
|
||
{ id: '8', name: '家电', icon: '📺' },
|
||
{ id: '9', name: '家居', icon: '🏠' },
|
||
{ id: '10', name: '母婴', icon: '👶' },
|
||
{ id: '11', name: '食品', icon: '🍎' },
|
||
{ id: '12', name: '运动', icon: '⚽' },
|
||
{ id: '13', name: '汽车', icon: '🚗' },
|
||
{ id: '14', name: '百货', icon: '🛒' },
|
||
{ id: '15', name: '图书', icon: '📚' },
|
||
{ id: '16', name: '玩具', icon: '🧸' },
|
||
{ id: '17', name: '珠宝', icon: '💎' },
|
||
{ id: '18', name: '手表', icon: '⌚' },
|
||
{ id: '19', name: '宠物', icon: '🐶' },
|
||
{ id: '20', name: '文具', icon: '✏️' }
|
||
],
|
||
|
||
flashSaleProducts: [
|
||
{
|
||
id: '1001',
|
||
name: '无线蓝牙耳机',
|
||
price: 299,
|
||
original_price: 599,
|
||
image: 'https://picsum.photos/200/200?random=1',
|
||
sales: 150,
|
||
soldPercent: 75,
|
||
tag: '秒杀'
|
||
},
|
||
{
|
||
id: '1002',
|
||
name: '运动T恤',
|
||
price: 79,
|
||
original_price: 159,
|
||
image: 'https://picsum.photos/200/200?random=2',
|
||
sales: 200,
|
||
soldPercent: 80,
|
||
tag: '爆款'
|
||
},
|
||
{
|
||
id: '1003',
|
||
name: '智能手环',
|
||
price: 199,
|
||
original_price: 299,
|
||
image: 'https://picsum.photos/200/200?random=3',
|
||
sales: 180,
|
||
soldPercent: 60,
|
||
tag: '新品'
|
||
},
|
||
{
|
||
id: '1004',
|
||
name: '电动牙刷',
|
||
price: 89,
|
||
original_price: 159,
|
||
image: 'https://picsum.photos/200/200?random=4',
|
||
sales: 250,
|
||
soldPercent: 90,
|
||
tag: '热卖'
|
||
},
|
||
{
|
||
id: '1005',
|
||
name: '保温杯',
|
||
price: 49,
|
||
original_price: 99,
|
||
image: 'https://picsum.photos/200/200?random=5',
|
||
sales: 300,
|
||
soldPercent: 85,
|
||
tag: '秒杀'
|
||
},
|
||
{
|
||
id: '1006',
|
||
name: '智能手表',
|
||
price: 399,
|
||
original_price: 599,
|
||
image: 'https://picsum.photos/200/200?random=6',
|
||
sales: 180,
|
||
soldPercent: 70,
|
||
tag: '爆款'
|
||
},
|
||
{
|
||
id: '1007',
|
||
name: '运动鞋',
|
||
price: 199,
|
||
original_price: 299,
|
||
image: 'https://picsum.photos/200/200?random=7',
|
||
sales: 220,
|
||
soldPercent: 80,
|
||
tag: '热卖'
|
||
},
|
||
{
|
||
id: '1008',
|
||
name: '保温饭盒',
|
||
price: 89,
|
||
original_price: 129,
|
||
image: 'https://picsum.photos/200/200?random=8',
|
||
sales: 190,
|
||
soldPercent: 75,
|
||
tag: '新品'
|
||
}
|
||
],
|
||
|
||
products: [
|
||
{
|
||
id: '2001',
|
||
name: '智能手机 5G全网通 大内存',
|
||
price: 3999,
|
||
original_price: 4999,
|
||
image: 'https://picsum.photos/300/400?random=6',
|
||
sales: 500,
|
||
shop: '官方旗舰店',
|
||
tag: '官方'
|
||
},
|
||
{
|
||
id: '2002',
|
||
name: '笔记本电脑 轻薄本 学生办公',
|
||
price: 5999,
|
||
original_price: 6999,
|
||
image: 'https://picsum.photos/300/300?random=7',
|
||
sales: 300,
|
||
shop: '品牌专卖店',
|
||
tag: '折扣'
|
||
},
|
||
{
|
||
id: '2003',
|
||
name: '运动鞋 透气舒适跑步鞋',
|
||
price: 299,
|
||
original_price: 499,
|
||
image: 'https://picsum.photos/300/500?random=8',
|
||
sales: 800,
|
||
shop: '运动专营店'
|
||
},
|
||
{
|
||
id: '2004',
|
||
name: '电饭煲 智能预约多功能',
|
||
price: 399,
|
||
original_price: 599,
|
||
image: 'https://picsum.photos/300/350?random=9',
|
||
sales: 450,
|
||
shop: '家电旗舰店',
|
||
tag: '热卖'
|
||
},
|
||
{
|
||
id: '2005',
|
||
name: '护肤品套装 保湿补水',
|
||
price: 299,
|
||
original_price: 399,
|
||
image: 'https://picsum.photos/300/450?random=10',
|
||
sales: 600,
|
||
shop: '美妆官方店'
|
||
},
|
||
{
|
||
id: '2006',
|
||
name: '儿童玩具积木益智',
|
||
price: 199,
|
||
original_price: 299,
|
||
image: 'https://picsum.photos/300/320?random=11',
|
||
sales: 350,
|
||
shop: '母婴专营店',
|
||
tag: '新品'
|
||
},
|
||
{
|
||
id: '2007',
|
||
name: '智能手表 心率监测',
|
||
price: 899,
|
||
original_price: 1299,
|
||
image: 'https://picsum.photos/300/380?random=12',
|
||
sales: 280,
|
||
shop: '数码旗舰店'
|
||
},
|
||
{
|
||
id: '2008',
|
||
name: '羽绒服 冬季保暖',
|
||
price: 499,
|
||
original_price: 899,
|
||
image: 'https://picsum.photos/300/420?random=13',
|
||
sales: 420,
|
||
shop: '服装旗舰店',
|
||
tag: '爆款'
|
||
}
|
||
]
|
||
}
|
||
|
||
// 生命周期
|
||
onMounted(() => {
|
||
// 获取状态栏高度
|
||
const systemInfo = uni.getSystemInfoSync()
|
||
statusBarHeight.value = systemInfo.statusBarHeight || 0
|
||
|
||
// 计算滚动区域高度
|
||
const windowHeight = systemInfo.windowHeight
|
||
const tabBarHeight = 50 // 假设tabBar高度为50px
|
||
scrollViewHeight.value = windowHeight - statusBarHeight.value - tabBarHeight
|
||
|
||
// 加载数据
|
||
loadMockData()
|
||
setupCountdown()
|
||
|
||
// 模拟获取购物车数量和未读消息数
|
||
cartCount.value = Math.floor(Math.random() * 5) + 1
|
||
})
|
||
|
||
onUnmounted(() => {
|
||
// 清理定时器
|
||
if (countdownTimer.value !== null) {
|
||
clearInterval(countdownTimer.value)
|
||
}
|
||
})
|
||
|
||
// 加载Mock数据
|
||
const loadMockData = () => {
|
||
bannerList.value = mockData.banners || []
|
||
categoryList.value = mockData.categories || []
|
||
flashSaleProducts.value = mockData.flashSaleProducts || []
|
||
productList.value = mockData.products || []
|
||
}
|
||
|
||
// 倒计时定时器
|
||
const countdownTimer = ref<any>(null)
|
||
const setupCountdown = () => {
|
||
countdownTimer.value = setInterval(() => {
|
||
let hours = parseInt(countdown.hours)
|
||
let minutes = parseInt(countdown.minutes)
|
||
let seconds = parseInt(countdown.seconds)
|
||
|
||
seconds--
|
||
if (seconds < 0) {
|
||
seconds = 59
|
||
minutes--
|
||
if (minutes < 0) {
|
||
minutes = 59
|
||
hours--
|
||
if (hours < 0) {
|
||
// 重置倒计时
|
||
hours = 2
|
||
minutes = 30
|
||
seconds = 15
|
||
}
|
||
}
|
||
}
|
||
|
||
countdown.hours = hours.toString().padStart(2, '0')
|
||
countdown.minutes = minutes.toString().padStart(2, '0')
|
||
countdown.seconds = seconds.toString().padStart(2, '0')
|
||
}, 1000)
|
||
}
|
||
|
||
// 事件处理函数
|
||
const showCityPicker = () => {
|
||
uni.showActionSheet({
|
||
itemList: ['北京市', '上海市', '广州市', '深圳市', '其他城市'],
|
||
success: (res) => {
|
||
const cities = ['北京市', '上海市', '广州市', '深圳市', '其他城市']
|
||
currentCity.value = cities[res.tapIndex]
|
||
}
|
||
})
|
||
}
|
||
|
||
// 切换商品分类
|
||
const switchCategory = (categoryId: string, index: number) => {
|
||
activeCategory.value = categoryId
|
||
|
||
// 这里可以添加根据分类筛选商品的逻辑
|
||
console.log('切换到分类:', categoryId)
|
||
|
||
// 滚动到选中的分类
|
||
const itemWidth = 80 // 每个分类项的宽度(包括margin)
|
||
scrollLeft.value = index * itemWidth
|
||
}
|
||
|
||
const switchSort = (sortId: string) => {
|
||
activeSort.value = sortId
|
||
// 这里可以添加根据排序方式筛选商品的逻辑
|
||
}
|
||
|
||
// 滚动事件
|
||
const onScroll = (e: any) => {
|
||
scrollLeft.value = e.detail.scrollLeft
|
||
}
|
||
|
||
// 下拉刷新
|
||
const onRefresh = () => {
|
||
refreshing.value = true
|
||
setTimeout(() => {
|
||
loadMockData()
|
||
refreshing.value = false
|
||
uni.showToast({
|
||
title: '刷新成功',
|
||
icon: 'success'
|
||
})
|
||
}, 1000)
|
||
}
|
||
|
||
// 上拉加载更多
|
||
const loadMore = () => {
|
||
if (!loading.value && hasMore.value) {
|
||
loading.value = true
|
||
setTimeout(() => {
|
||
// 模拟加载更多数据
|
||
const newProducts = [...mockData.products].map((item, index) => ({
|
||
...item,
|
||
id: `300${index}`,
|
||
price: item.price + Math.floor(Math.random() * 100)
|
||
}))
|
||
productList.value = [...productList.value, ...newProducts]
|
||
loading.value = false
|
||
hasMore.value = productList.value.length < 20 // 假设最多显示20个商品
|
||
}, 1500)
|
||
}
|
||
}
|
||
|
||
// 导航函数 - 修改消息为跳转到消息tab页
|
||
const navigateToSearch = () => uni.navigateTo({ url: '/pages/mall/consumer/search' })
|
||
const navigateToCategory = (category?: any) => {
|
||
if (category) {
|
||
uni.navigateTo({ url: `/pages/mall/consumer/category?id=${category.id}&name=${category.name}` })
|
||
} else {
|
||
uni.switchTab({ url: '/pages/mall/consumer/category' })
|
||
}
|
||
}
|
||
const navigateToProduct = (product: any) => {
|
||
uni.navigateTo({ url: `/pages/mall/consumer/product-detail?id=${product.id}` })
|
||
}
|
||
const navigateToCoupons = () => uni.navigateTo({ url: '/pages/mall/consumer/coupons' })
|
||
const navigateToMessages = () => uni.switchTab({ url: '/pages/mall/consumer/messages' })
|
||
const navigateToFlashSale = () => uni.navigateTo({ url: '/pages/mall/consumer/flash-sale' })
|
||
const navigateToBrand = () => uni.navigateTo({ url: '/pages/mall/consumer/brand' })
|
||
const navigateToCart = () => uni.switchTab({ url: '/pages/mall/consumer/cart' })
|
||
const navigateToDailyDeals = () => uni.navigateTo({ url: '/pages/mall/consumer/daily-deals' })
|
||
const navigateToGroupBuy = () => uni.navigateTo({ url: '/pages/mall/consumer/group-buy' })
|
||
</script>
|
||
|
||
<style>
|
||
/* 重置默认样式 - 确保不受全局样式影响 */
|
||
.consumer-home * {
|
||
box-sizing: border-box;
|
||
margin: 0;
|
||
padding: 0;
|
||
}
|
||
|
||
.consumer-home {
|
||
width: 100%;
|
||
min-height: 100vh;
|
||
background: #f5f5f5;
|
||
display: flex;
|
||
flex-direction: column;
|
||
position: relative;
|
||
}
|
||
|
||
/* 自定义导航栏 - 简化版 */
|
||
.custom-navbar {
|
||
background: #ff5000;
|
||
width: 100%;
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
z-index: 1000;
|
||
}
|
||
|
||
.nav-content {
|
||
height: 44px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 0 15px;
|
||
color: white;
|
||
}
|
||
|
||
.location {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-shrink: 0;
|
||
padding: 5px 10px;
|
||
background: rgba(255, 255, 255, 0.2);
|
||
border-radius: 15px;
|
||
}
|
||
|
||
.location-icon {
|
||
font-size: 14px;
|
||
margin-right: 4px;
|
||
}
|
||
|
||
.location-text {
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
max-width: 60px;
|
||
}
|
||
|
||
.location-arrow {
|
||
font-size: 10px;
|
||
margin-left: 4px;
|
||
color: rgba(255, 255, 255, 0.8);
|
||
}
|
||
|
||
.nav-icons {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 15px;
|
||
}
|
||
|
||
.icon-item {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 30px;
|
||
height: 30px;
|
||
position: relative;
|
||
}
|
||
|
||
.icon {
|
||
font-size: 20px;
|
||
}
|
||
|
||
.message-badge, .cart-badge {
|
||
position: absolute;
|
||
top: -5px;
|
||
right: -5px;
|
||
background: #ff3b30;
|
||
color: white;
|
||
font-size: 10px;
|
||
width: 16px;
|
||
height: 16px;
|
||
border-radius: 50%;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
/* 主内容区 */
|
||
.main-content {
|
||
background: #f5f5f5;
|
||
margin-top: 44px;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 商品分类区域 - 修复横向滚动 */
|
||
.category-section {
|
||
background: white;
|
||
width: 100%;
|
||
padding: 15px 0;
|
||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||
margin-bottom: 5px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
}
|
||
|
||
/* 商品分类横向滚动区域 */
|
||
.category-scroll {
|
||
white-space: nowrap;
|
||
width: 100%;
|
||
overflow-x: auto;
|
||
-webkit-overflow-scrolling: touch;
|
||
height: 90px;
|
||
}
|
||
|
||
.category-container {
|
||
display: flex;
|
||
flex-direction: row;
|
||
padding: 10px 15px;
|
||
}
|
||
|
||
.category-item {
|
||
flex-shrink: 0;
|
||
margin-right: 15px;
|
||
width: 70px;
|
||
height: 70px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
transition: all 0.3s ease;
|
||
position: relative;
|
||
}
|
||
|
||
.category-item.active .category-icon-wrapper {
|
||
background: #ff5000;
|
||
transform: scale(1.1);
|
||
box-shadow: 0 4px 12px rgba(255, 80, 0, 0.3);
|
||
}
|
||
|
||
.category-item.active .category-icon {
|
||
color: white;
|
||
}
|
||
|
||
.category-item.active .category-name {
|
||
color: #ff5000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* 添加活动指示器 */
|
||
.category-item.active::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 50%;
|
||
transform: translateX(-50%);
|
||
width: 20px;
|
||
height: 3px;
|
||
background: #ff5000;
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.category-icon-wrapper {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: 24px;
|
||
background: linear-gradient(135deg, #f5f5f5, #e8e8e8);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-bottom: 6px;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.category-icon {
|
||
font-size: 24px;
|
||
color: #666;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
.category-name {
|
||
font-size: 12px;
|
||
color: #333;
|
||
text-align: center;
|
||
white-space: nowrap;
|
||
overflow: hidden;
|
||
text-overflow: ellipsis;
|
||
width: 100%;
|
||
line-height: 1.2;
|
||
transition: all 0.3s ease;
|
||
}
|
||
|
||
/* 搜索栏 */
|
||
.search-section {
|
||
background: white;
|
||
padding: 12px 15px;
|
||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
.search-container {
|
||
width: 100%;
|
||
}
|
||
|
||
.search-box {
|
||
background: #f5f5f5;
|
||
border-radius: 25px;
|
||
padding: 12px 20px;
|
||
display: flex;
|
||
align-items: center;
|
||
width: 100%;
|
||
height: 45px;
|
||
border: 1px solid #eee;
|
||
}
|
||
|
||
.search-icon {
|
||
color: #999;
|
||
margin-right: 10px;
|
||
font-size: 18px;
|
||
}
|
||
|
||
.search-placeholder {
|
||
color: #999;
|
||
font-size: 15px;
|
||
flex: 1;
|
||
}
|
||
|
||
/* 轮播图区域 */
|
||
.banner-section {
|
||
background: white;
|
||
width: 100%;
|
||
overflow: hidden;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.banner-swiper {
|
||
height: 200px;
|
||
width: 100%;
|
||
}
|
||
|
||
.banner-image {
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
|
||
/* 快捷入口 - 横向排列 */
|
||
.quick-actions {
|
||
background: white;
|
||
padding: 20px 0;
|
||
margin: 10px;
|
||
border-radius: 12px;
|
||
display: flex;
|
||
flex-direction: row;
|
||
justify-content: space-around;
|
||
align-items: center;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||
width: calc(100% - 20px);
|
||
}
|
||
|
||
.action-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 20%;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.action-icon {
|
||
width: 48px;
|
||
height: 48px;
|
||
border-radius: 24px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 22px;
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.action-icon.flash {
|
||
background: linear-gradient(135deg, #ff3b30, #ff9500);
|
||
color: white;
|
||
}
|
||
|
||
.action-icon.coupon {
|
||
background: linear-gradient(135deg, #34c759, #30d158);
|
||
color: white;
|
||
}
|
||
|
||
.action-icon.daily {
|
||
background: linear-gradient(135deg, #ff9500, #ffcc00);
|
||
color: white;
|
||
}
|
||
|
||
.action-icon.brand {
|
||
background: linear-gradient(135deg, #af52de, #ff2d55);
|
||
color: white;
|
||
}
|
||
|
||
.action-icon.group {
|
||
background: linear-gradient(135deg, #007aff, #5856d6);
|
||
color: white;
|
||
}
|
||
|
||
.action-text {
|
||
font-size: 13px;
|
||
color: #333;
|
||
font-weight: 500;
|
||
text-align: center;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 限时秒杀 - 新版横向布局 */
|
||
.flash-sale-section {
|
||
background: linear-gradient(135deg, #fff0e8, #ffece6);
|
||
margin: 10px;
|
||
border-radius: 12px;
|
||
padding: 18px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||
border: 1px solid #ffddd1;
|
||
width: calc(100% - 20px);
|
||
}
|
||
|
||
/* 限时秒杀头部 - 横向排列 */
|
||
.section-header {
|
||
margin-bottom: 18px;
|
||
width: 100%;
|
||
}
|
||
|
||
.header-content {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 15px;
|
||
}
|
||
|
||
.title-with-icon {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.flash-icon, .recommend-icon {
|
||
color: #ff5000;
|
||
font-size: 20px;
|
||
}
|
||
|
||
.section-title {
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
color: #ff5000;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
/* 倒计时样式调整 - 横向排列 */
|
||
.countdown-wrapper {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
background: #ff5000;
|
||
padding: 6px 12px;
|
||
border-radius: 6px;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.countdown-label {
|
||
font-size: 13px;
|
||
color: white;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.time-box {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
}
|
||
|
||
.time {
|
||
background: white;
|
||
color: #ff5000;
|
||
padding: 4px 8px;
|
||
border-radius: 4px;
|
||
font-size: 14px;
|
||
min-width: 26px;
|
||
text-align: center;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.colon {
|
||
color: white;
|
||
font-size: 14px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.more-link {
|
||
display: flex;
|
||
align-items: center;
|
||
color: #999;
|
||
font-size: 14px;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.more-link .arrow {
|
||
margin-left: 5px;
|
||
font-size: 18px;
|
||
}
|
||
|
||
/* 限时秒杀商品网格布局 */
|
||
.flash-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 12px;
|
||
width: 100%;
|
||
}
|
||
|
||
.flash-product {
|
||
background: white;
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
border: 1px solid #ffddd1;
|
||
box-shadow: 0 3px 10px rgba(255, 80, 0, 0.12);
|
||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||
}
|
||
|
||
.flash-product:active {
|
||
transform: scale(0.98);
|
||
box-shadow: 0 2px 8px rgba(255, 80, 0, 0.2);
|
||
}
|
||
|
||
.product-image-wrapper {
|
||
position: relative;
|
||
width: 100%;
|
||
height: 0;
|
||
padding-bottom: 100%; /* 保持正方形 */
|
||
overflow: hidden;
|
||
}
|
||
|
||
.product-image {
|
||
position: absolute;
|
||
top: 0;
|
||
left: 0;
|
||
width: 100%;
|
||
height: 100%;
|
||
display: block;
|
||
}
|
||
|
||
.product-tag {
|
||
position: absolute;
|
||
top: 8px;
|
||
left: 8px;
|
||
background: #ff5000;
|
||
color: white;
|
||
font-size: 11px;
|
||
padding: 3px 10px;
|
||
border-radius: 12px;
|
||
font-weight: bold;
|
||
z-index: 1;
|
||
}
|
||
|
||
.price-info {
|
||
padding: 12px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
}
|
||
|
||
.flash-price {
|
||
color: #ff5000;
|
||
font-size: 18px;
|
||
font-weight: bold;
|
||
text-align: center;
|
||
width: 100%;
|
||
}
|
||
|
||
.original-price {
|
||
color: #999;
|
||
font-size: 13px;
|
||
text-decoration: line-through;
|
||
margin: 6px 0;
|
||
text-align: center;
|
||
width: 100%;
|
||
}
|
||
|
||
.progress-container {
|
||
width: 100%;
|
||
margin-top: 8px;
|
||
}
|
||
|
||
.progress-bar {
|
||
width: 100%;
|
||
height: 8px;
|
||
background: #ffece6;
|
||
border-radius: 4px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.progress-inner {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, #ff9500, #ff5000);
|
||
border-radius: 4px;
|
||
}
|
||
|
||
.sold-text {
|
||
font-size: 11px;
|
||
color: #ff5000;
|
||
text-align: center;
|
||
width: 100%;
|
||
margin-top: 4px;
|
||
}
|
||
|
||
/* 为你推荐 - 瀑布流布局 */
|
||
.recommend-section {
|
||
background: white;
|
||
margin: 10px;
|
||
border-radius: 12px;
|
||
padding: 18px;
|
||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
|
||
width: calc(100% - 20px);
|
||
}
|
||
|
||
/* 为你推荐头部 */
|
||
.recommend-section .section-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 18px;
|
||
}
|
||
|
||
/* 排序选项 - 横向排列 */
|
||
.sort-options {
|
||
display: flex;
|
||
gap: 15px;
|
||
align-items: center;
|
||
flex-wrap: nowrap;
|
||
overflow-x: auto;
|
||
padding-bottom: 5px;
|
||
}
|
||
|
||
.sort-option {
|
||
font-size: 14px;
|
||
color: #666;
|
||
padding: 5px 0;
|
||
position: relative;
|
||
white-space: nowrap;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.sort-option.active {
|
||
color: #ff5000;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.sort-option.active::after {
|
||
content: '';
|
||
position: absolute;
|
||
bottom: 0;
|
||
left: 0;
|
||
right: 0;
|
||
height: 2px;
|
||
background: #ff5000;
|
||
border-radius: 1px;
|
||
}
|
||
|
||
/* 瀑布流布局 */
|
||
.waterfall-container {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
width: 100%;
|
||
margin-top: 18px;
|
||
}
|
||
|
||
.waterfall-column {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
}
|
||
|
||
.left-column {
|
||
margin-right: 6px;
|
||
}
|
||
|
||
.right-column {
|
||
margin-left: 6px;
|
||
}
|
||
|
||
.product-card {
|
||
background: white;
|
||
border-radius: 10px;
|
||
overflow: hidden;
|
||
box-shadow: 0 3px 12px rgba(0, 0, 0, 0.08);
|
||
width: 100%;
|
||
}
|
||
|
||
.product-image-wrapper {
|
||
position: relative;
|
||
width: 100%;
|
||
background: #f8f8f8;
|
||
}
|
||
|
||
.product-image {
|
||
width: 100%;
|
||
display: block;
|
||
}
|
||
|
||
.product-info {
|
||
padding: 15px;
|
||
}
|
||
|
||
.product-title {
|
||
font-size: 15px;
|
||
color: #333;
|
||
line-height: 1.4;
|
||
height: 42px;
|
||
overflow: hidden;
|
||
display: -webkit-box;
|
||
-webkit-line-clamp: 2;
|
||
-webkit-box-orient: vertical;
|
||
margin-bottom: 12px;
|
||
font-weight: 500;
|
||
}
|
||
|
||
.price-section {
|
||
display: flex;
|
||
align-items: baseline;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.current-price {
|
||
color: #ff5000;
|
||
}
|
||
|
||
.price-symbol {
|
||
font-size: 13px;
|
||
}
|
||
|
||
.price-value {
|
||
font-size: 20px;
|
||
font-weight: bold;
|
||
}
|
||
|
||
.original-price {
|
||
color: #999;
|
||
font-size: 13px;
|
||
text-decoration: line-through;
|
||
margin-left: 10px;
|
||
}
|
||
|
||
.product-meta {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
font-size: 13px;
|
||
}
|
||
|
||
.sales-count {
|
||
color: #999;
|
||
}
|
||
|
||
.shop-info {
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.shop-name {
|
||
color: #666;
|
||
}
|
||
|
||
/* 加载状态 */
|
||
.loading-container {
|
||
padding: 30px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 100%;
|
||
}
|
||
|
||
.loading-spinner {
|
||
width: 30px;
|
||
height: 30px;
|
||
border: 3px solid #f0f5ff;
|
||
border-top-color: #ff5000;
|
||
border-radius: 50%;
|
||
animation: spin 1s linear infinite;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
@keyframes spin {
|
||
0% { transform: rotate(0deg); }
|
||
100% { transform: rotate(360deg); }
|
||
}
|
||
|
||
.loading-text {
|
||
color: #999;
|
||
font-size: 14px;
|
||
}
|
||
|
||
.no-more {
|
||
text-align: center;
|
||
color: #999;
|
||
font-size: 13px;
|
||
padding: 30px 0;
|
||
border-top: 1px solid #f0f0f0;
|
||
margin-top: 10px;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 安全区域 */
|
||
.safe-area {
|
||
height: 20px;
|
||
width: 100%;
|
||
}
|
||
|
||
/* 为分类项添加点击反馈 */
|
||
.category-item:active {
|
||
opacity: 0.7;
|
||
transform: scale(0.98);
|
||
}
|
||
|
||
/* 确保分类图标在点击时有更好的视觉效果 */
|
||
.category-icon-wrapper:active {
|
||
transform: scale(0.95);
|
||
}
|
||
|
||
/* 响应式适配 */
|
||
@media screen and (max-width: 320px) {
|
||
.category-item {
|
||
width: 65px;
|
||
margin-right: 12px;
|
||
}
|
||
|
||
.flash-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 10px;
|
||
}
|
||
|
||
/* 限时秒杀头部适配小屏幕 */
|
||
.header-content {
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
}
|
||
|
||
.countdown-wrapper {
|
||
order: 3;
|
||
width: 100%;
|
||
justify-content: center;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.more-link {
|
||
order: 2;
|
||
}
|
||
|
||
.sort-options {
|
||
gap: 12px;
|
||
font-size: 13px;
|
||
}
|
||
}
|
||
|
||
@media screen and (min-width: 321px) and (max-width: 375px) {
|
||
.category-item {
|
||
width: 68px;
|
||
margin-right: 14px;
|
||
}
|
||
|
||
.flash-grid {
|
||
grid-template-columns: repeat(2, 1fr);
|
||
gap: 12px;
|
||
}
|
||
|
||
.header-content {
|
||
flex-wrap: wrap;
|
||
gap: 10px;
|
||
}
|
||
|
||
.countdown-wrapper {
|
||
order: 3;
|
||
width: 100%;
|
||
justify-content: center;
|
||
margin-top: 5px;
|
||
}
|
||
|
||
.more-link {
|
||
order: 2;
|
||
}
|
||
|
||
.sort-options {
|
||
gap: 15px;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
@media screen and (min-width: 376px) and (max-width: 414px) {
|
||
.category-item {
|
||
width: 72px;
|
||
margin-right: 15px;
|
||
}
|
||
|
||
.flash-grid {
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 12px;
|
||
}
|
||
|
||
.header-content {
|
||
flex-wrap: nowrap;
|
||
gap: 15px;
|
||
}
|
||
|
||
.countdown-wrapper {
|
||
order: unset;
|
||
width: auto;
|
||
justify-content: flex-start;
|
||
margin-top: 0;
|
||
}
|
||
|
||
.more-link {
|
||
order: unset;
|
||
}
|
||
|
||
.sort-options {
|
||
gap: 18px;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
@media screen and (min-width: 415px) {
|
||
.category-item {
|
||
width: 75px;
|
||
margin-right: 18px;
|
||
}
|
||
|
||
.flash-grid {
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 15px;
|
||
}
|
||
|
||
.header-content {
|
||
flex-wrap: nowrap;
|
||
gap: 20px;
|
||
}
|
||
|
||
.sort-options {
|
||
gap: 20px;
|
||
font-size: 14px;
|
||
}
|
||
}
|
||
|
||
/* 针对平板设备的适配 */
|
||
@media screen and (min-width: 768px) {
|
||
.flash-grid {
|
||
grid-template-columns: repeat(5, 1fr);
|
||
gap: 16px;
|
||
}
|
||
|
||
.flash-product {
|
||
border-radius: 12px;
|
||
}
|
||
|
||
.product-image-wrapper {
|
||
padding-bottom: 100%;
|
||
}
|
||
|
||
.sort-options {
|
||
gap: 25px;
|
||
font-size: 15px;
|
||
}
|
||
}
|
||
</style> |