zdtap-uniapp-main/pages/index/brandHome.vue

1123 lines
26 KiB
Vue
Raw Normal View History

2025-03-29 16:01:43 +08:00
<template>
<view class="page-content">
<!-- 自定义导航栏 -->
<view class="custom-nav" :style="{ paddingTop: statusBarHeight + 'px' }">
<view class="nav-content">
<view class="back-btn" @click="goBack">
<text class="cuIcon-back"></text>
</view>
</view>
</view>
<!-- 品牌广告图片 -->
<view class="banner-container">
<image class="banner" :src="breweryInfo.brandCover" mode="aspectFill"></image>
<view class="banner-overlay"></view>
</view>
<!-- 品牌信息卡片 -->
2025-03-29 16:01:43 +08:00
<view class="brand-header">
<view class="brand-info">
<view class="flex align-start justify-between">
2025-03-29 16:01:43 +08:00
<view class="flex align-center">
<image :src="breweryInfo.brandLogo" class="brand-logo" mode="aspectFill"></image>
2025-03-29 16:01:43 +08:00
<view class="flex flex-col">
<text class="brand-name">{{ breweryInfo.brandName}}</text>
<view class="brand-location">
<text class="cuIcon-location"></text>
<text>{{breweryInfo.country}}·{{breweryInfo.province}}·{{breweryInfo.city}}</text>
</view>
2025-03-29 16:01:43 +08:00
</view>
</view>
<view class="action-buttons">
<view class="action-btn favor-btn" @click="favorBreweryFun(1)" v-if="!isFavor">
<image src="/static/heart-add.png" class="action-icon" mode="aspectFit"></image>
</view>
<view class="action-btn favor-btn active" @click="favorBreweryFun(2)" v-else>
<image src="/static/heart-tick.png" class="action-icon" mode="aspectFit"></image>
</view>
<view class="action-btn share-btn" @click="share">
<image src="/static/send.png" class="action-icon" mode="aspectFit"></image>
</view>
2025-03-29 16:01:43 +08:00
</view>
</view>
<view class="brand-stats">
<view class="stat-item">
<text class="stat-value">{{ beerTotal}}</text>
<text class="stat-label">在售酒款</text>
2025-03-29 16:01:43 +08:00
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<text class="stat-value">{{ breweryInfo.buildingDate && breweryInfo.buildingDate.substr(0,4)}}</text>
<text class="stat-label">since</text>
2025-03-29 16:01:43 +08:00
</view>
<view class="stat-divider"></view>
<view class="stat-item">
<text class="stat-value">{{myCoin || '--'}}</text>
<text class="stat-label">啤酒币</text>
2025-03-29 16:01:43 +08:00
</view>
</view>
<view class="brand-desc-container">
<view class="brand-desc">{{breweryInfo.desc}}</view>
</view>
</view>
</view>
<!-- 标签页导航 -->
<view class="tab-nav">
<view
class="tab-item"
:class="{'active':currentTab == 1}"
@click="changeTab(1)"
>
<text>在售酒款</text>
2025-03-29 16:01:43 +08:00
</view>
<view
class="tab-item"
:class="{'active':currentTab == 2}"
@click="changeTab(2)"
>
<text>累积活动</text>
</view>
<view
class="tab-item"
:class="{'active':currentTab == 3}"
@click="changeTab(3)"
>
<text>啤酒币兑换</text>
2025-03-29 16:01:43 +08:00
</view>
</view>
<!-- 内容区域 -->
2025-03-29 16:01:43 +08:00
<view class="content-box">
<!-- 在售酒款 -->
<view v-if="currentTab == 1" class="tab-content">
<scroll-view
scroll-y
enable-flex
class="scroll-container"
@scrolltolower="onScrollToLower"
>
<view class="beer-grid">
<beer-card
v-for="(item, index) in beerList"
:key="index"
:item="item"
@click="toReview(item)"
v-if="item && item.id"
></beer-card>
</view>
<view
class="loading-state"
:class="loading ? 'loading' : beerList.length >= beerTotal ? 'no-more' : ''"
v-if="beerList.length > 0"
>
<view v-if="loading" class="loading-text">
<text class="cuIcon-loading2 iconfont-spin"></text>
<text>加载中...</text>
</view>
<text v-else-if="beerList.length >= beerTotal" class="no-more-text">没有更多了</text>
</view>
<view class="empty-state" v-if="!loading && beerList.length === 0">
<image src="/static/empty.png" mode="aspectFit" class="empty-image"></image>
<text class="empty-text">暂无在售酒款</text>
</view>
2025-03-29 16:01:43 +08:00
</scroll-view>
</view>
<!-- 累积活动 -->
<view v-if="currentTab == 2" class="tab-content">
<scroll-view
scroll-y
enable-flex
class="scroll-container"
@scrolltolower="onScrollToLower"
>
<!-- 空状态 -->
<view v-if="!loading && activityList.length === 0" class="empty-state">
<image src="/static/images/empty.png" class="empty-image" mode="aspectFit"></image>
<text class="empty-text">暂无活动</text>
</view>
<!-- 活动列表 -->
<view class="activity-list" v-else>
<activity-item
v-for="(item, index) in activityList"
:key="index"
:item="item"
@click="toActivityDetail"
@review="toReview"
></activity-item>
</view>
<!-- 加载状态 -->
<view
class="loading-state"
:class="loading ? 'loading' : activityList.length >= activityTotal ? 'no-more' : ''"
v-if="activityList.length > 0"
>
<view v-if="loading" class="loading-text">
<text class="cuIcon-loading2 iconfont-spin"></text>
<text>加载中...</text>
2025-03-29 16:01:43 +08:00
</view>
<text v-else-if="activityList.length >= activityTotal" class="no-more-text">没有更多了</text>
2025-03-29 16:01:43 +08:00
</view>
</scroll-view>
</view>
2025-03-29 16:01:43 +08:00
<!-- 啤酒币兑换 -->
<view v-if="currentTab == 3" class="tab-content">
<scroll-view
scroll-y
enable-flex
class="scroll-container"
@scrolltolower="onScrollToLower"
>
<view class="goods-grid">
<view
class="goods-item"
v-for="(item, index) in goodsList"
:key="index"
@click="toDetail(item)"
>
<image class="goods-image" :src="item.goodsCover" mode="aspectFill"></image>
<view class="goods-info">
<view class="goods-title text-cut">{{item.goodsName}}</view>
<view class="goods-price">
<view class="price-left">
<text class="price-num">{{item.redeemedNum}}</text>
<text class="cuIcon-rechargefill coin-icon"></text>
</view>
<text class="brand-name">{{item.brandName}}</text>
</view>
2025-03-29 16:01:43 +08:00
</view>
</view>
</view>
<view
class="loading-state"
:class="loading ? 'loading' : goodsList.length >= goodsTotal ? 'no-more' : ''"
v-if="goodsList.length > 0"
>
<view v-if="loading" class="loading-text">
<text class="cuIcon-loading2 iconfont-spin"></text>
<text>加载中...</text>
</view>
<text v-else-if="goodsList.length >= goodsTotal" class="no-more-text">没有更多了</text>
</view>
<view class="empty-state" v-if="!loading && goodsList.length === 0">
<image src="/static/empty.png" mode="aspectFit" class="empty-image"></image>
<text class="empty-text">暂无兑换商品</text>
</view>
2025-03-29 16:01:43 +08:00
</scroll-view>
</view>
</view>
<!-- 登录弹窗组件 -->
2025-03-29 16:01:43 +08:00
<loginPopup ref="loginRef" @loginSuccess="loginSuccess"></loginPopup>
</view>
</template>
<script>
import {
getBreweryInfo,
getBreweryActivities,
getBreweryBeerList,
getBreweryGoodsList,
favorBrewery,
getBreweryFavorStatus,
getBreweryCoinBalance
} from '@/api/bar.js'
import loginPopup from '@/components/loginPopup.vue';
import ActivityItem from '@/components/ActivityItem.vue';
import BeerCard from '@/components/BeerCard.vue';
2025-03-29 16:01:43 +08:00
export default {
components: {
loginPopup,
ActivityItem,
BeerCard
2025-03-29 16:01:43 +08:00
},
data() {
return {
statusBarHeight: 0, // 状态栏高度
showTabNav: false,
scrollTop: 0,
2025-03-29 16:01:43 +08:00
breweryId: '',
currentTab: 1,
breweryInfo: {}, // 品牌方详情
activityList: [],
goodsList: [],
beerList: [],
loading: false,
beerTotal: 0, // 在售酒款总数
goodsTotal: 0, // 兑换商品总数
activityTotal: 0, // 活动总数
total: 0,
formattedDate: '', // 当前年月日
isFavor: false, // 是否收藏
myCoin: 0, // 我的啤酒币
queryForm: {
pageNum: 1,
pageSize: 5,
2025-03-29 16:01:43 +08:00
id: ''
},
2025-03-29 16:01:43 +08:00
};
},
onLoad({
breweryId
}) {
// 获取状态栏高度
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight
2025-03-29 16:01:43 +08:00
this.breweryId = breweryId
this.queryForm.id = breweryId
this.getBreweryInfoFun()
this.getBreweryActivitiesFun()
this.getBreweryBeerListFun()
this.getBreweryGoodsListFun()
this.getDate()
this.getBreweryFavorStatusFun()
this.getBreweryCoinBalanceFun() // 啤酒币余额
},
methods: {
// 返回上一页
goBack() {
uni.navigateBack()
},
2025-03-29 16:01:43 +08:00
changeTab(index) {
this.currentTab = index
this.queryForm.pageNum = 1
if (index == 1) {
this.beerList = []
this.getBreweryBeerListFun()
} else if (index == 2) {
this.activityList = []
this.getBreweryActivitiesFun()
2025-03-29 16:01:43 +08:00
} else if (index == 3) {
this.goodsList = []
this.getBreweryGoodsListFun()
}
},
// 登录成功回调
loginSuccess() {
this.getBreweryFavorStatusFun()
this.getBreweryCoinBalanceFun()
},
share() {
uni.downloadFile({
url: this.breweryInfo.brandCover,
success: (res) => {
console.log(res)
// #ifdef MP-WEIXIN
uni.showShareImageMenu({
provider: 'weixin',
// path: '/pages/index/featureInfo?id=' + this.id,
path: res.tempFilePath,
shareType: 0,
success: (res) => {
console.log(res)
},
fail: (err) => {
console.log(err)
}
})
// #endif
}
})
},
// 啤酒币余额
getBreweryCoinBalanceFun() {
getBreweryCoinBalance(this.breweryId).then(res => {
if (res.data) {
this.myCoin = res.data.balance || 0
} else {
this.myCoin = 0
2025-03-29 16:01:43 +08:00
}
}).catch(err => {
console.error('获取啤酒币余额失败:', err)
this.myCoin = 0
2025-03-29 16:01:43 +08:00
})
},
// 收藏品牌方状态
getBreweryFavorStatusFun() {
getBreweryFavorStatus(this.breweryId).then(res => {
if (res.data) {
this.isFavor = true
} else {
this.isFavor = false
}
}).catch(err => {
console.error('获取收藏状态失败:', err)
uni.showToast({
title: err.msg || '获取收藏状态失败,请稍后重试',
icon: 'none'
})
2025-03-29 16:01:43 +08:00
})
},
// 获取当前年月日
getDate() {
const currentDate = new Date();
// 获取年份
const year = currentDate.getFullYear();
// 获取月份(注意:月份是从 0 开始计数的,所以要加 1
const month = String(currentDate.getMonth() + 1).padStart(2, '0');
// 获取日期
const day = String(currentDate.getDate()).padStart(2, '0');
// 格式化日期为 YYYY-MM-DD 格式
this.formattedDate = `${year}-${month}-${day}`;
},
// 计算剩余天数
getRemainingDays(date) {
const targetDate = new Date(date);
const currentDate = new Date();
const timeDiff = targetDate.getTime() - currentDate.getTime();
const remainingDays = Math.ceil(timeDiff / (1000 * 3600 * 24));
return remainingDays;
},
// 品牌方详情
getBreweryInfoFun() {
getBreweryInfo(this.breweryId).then(res => {
this.breweryInfo = res.data
}).catch(err => {
console.error('获取品牌方详情失败:', err)
uni.showToast({
title: err.msg || '获取品牌方详情失败,请稍后重试',
icon: 'none'
})
2025-03-29 16:01:43 +08:00
})
},
// 累积活动
getBreweryActivitiesFun() {
this.loading = true
getBreweryActivities(this.queryForm).then(res => {
this.loading = false
this.activityTotal = res.total
if (res.rows && res.rows.length > 0) {
let arr = res.rows.map(it => {
it.remainingDays = this.getRemainingDays(it.endDate)
return it
})
this.activityList = [...this.activityList, ...arr]
2025-03-29 16:01:43 +08:00
}
}).catch(err => {
console.error('获取累积活动失败:', err)
uni.showToast({
title: err.msg || '获取活动列表失败,请稍后重试',
icon: 'none'
})
2025-03-29 16:01:43 +08:00
this.loading = false
})
},
// 在售酒款
getBreweryBeerListFun() {
this.loading = true
getBreweryBeerList(this.queryForm).then(res => {
this.loading = false
this.beerTotal = res.total
if (res.rows && res.rows.length > 0) {
this.beerList = [...this.beerList, ...res.rows.filter(item => item && item.id)]
2025-03-29 16:01:43 +08:00
}
}).catch(err => {
console.error('获取在售酒款失败:', err)
uni.showToast({
title: err.msg || '获取酒款列表失败,请稍后重试',
icon: 'none'
})
2025-03-29 16:01:43 +08:00
this.loading = false
})
},
// 兑换商品
getBreweryGoodsListFun() {
this.loading = true
getBreweryGoodsList(this.queryForm).then(res => {
this.loading = false
this.goodsTotal = res.total
if (res.rows && res.rows.length > 0) {
this.goodsList = [...this.goodsList, ...res.rows]
2025-03-29 16:01:43 +08:00
}
}).catch(err => {
console.error('获取兑换商品失败:', err)
uni.showToast({
title: err.msg || '获取商品列表失败,请稍后重试',
icon: 'none'
})
2025-03-29 16:01:43 +08:00
this.loading = false
})
},
// 滚动加载更多
onScrollToLower() {
if (this.loading) return
if (this.currentTab === 1 && this.activityList.length < this.activityTotal) {
this.queryForm.pageNum++
this.getBreweryActivitiesFun()
} else if (this.currentTab === 2 && this.beerList.length < this.beerTotal) {
this.queryForm.pageNum++
this.getBreweryBeerListFun()
} else if (this.currentTab === 3 && this.goodsList.length < this.goodsTotal) {
2025-03-29 16:01:43 +08:00
this.queryForm.pageNum++
this.getBreweryGoodsListFun()
}
},
// 收藏品牌方
favorBreweryFun(status) {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
// 检查认证状态
const barInfo = uni.getStorageSync('barInfo')
if (!barInfo) {
uni.showModal({
title: '提示',
content: '请先认证门店',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
}
// 处理不同的认证状态
if (barInfo.authState === 0) {
uni.showModal({
title: '提示',
content: '请先认证门店',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
return
} else if (barInfo.authState === 2) {
uni.showToast({
title: '您的门店正在认证中,请耐心等待',
icon: 'none'
})
return
}
2025-03-29 16:01:43 +08:00
let data = {
breweryId: this.breweryId,
status
}
favorBrewery(data).then(res => {
if (status == 1) {
this.isFavor = true
2025-03-29 16:01:43 +08:00
uni.showToast({
title: '收藏成功',
icon: 'success'
})
} else {
this.isFavor = false
2025-03-29 16:01:43 +08:00
uni.showToast({
title: '取消收藏',
icon: 'none'
})
}
}).catch(err => {
if (err.code === 500 && err.msg.includes('门店未认证')) {
uni.showModal({
title: '提示',
content: '请先认证门店',
showCancel: true,
success: (res) => {
if (res.confirm) {
uni.navigateTo({
url: '/pages/index/registration'
})
}
}
})
} else {
uni.showToast({
title: err.msg || '操作失败',
icon: 'none'
})
}
2025-03-29 16:01:43 +08:00
})
},
// 跳转详情
toDetail(item) {
uni.navigateTo({
url: "/pagesCoin/goodsDetail?id=" + item.id + "&breweryId=" + item.breweryId
})
},
// 跳转活动详情
toActivityDetail(item) {
uni.navigateTo({
url: "/pagesActivity/activityDetail?id=" + item.id
})
},
// 跳转酒评
2025-03-29 16:01:43 +08:00
toReview(it) {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.open()
return
}
2025-03-29 16:01:43 +08:00
uni.navigateTo({
url: "/pages/index/review?beerId=" + it.id
})
},
onPageScroll(e) {
const tabNavThreshold = 300; // 设置一个阈值,当滚动超过这个值时显示导航
this.scrollTop = e.scrollTop;
this.showTabNav = this.scrollTop > tabNavThreshold;
},
2025-03-29 16:01:43 +08:00
},
}
</script>
<style lang="scss" scoped>
.page-content {
min-height: 100vh;
background-color: #F6F7FB;
position: relative;
/* 导航栏样式 */
.custom-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 999;
background: transparent;
.nav-content {
height: 44px;
display: flex;
align-items: center;
padding: 0 32rpx;
.back-btn {
width: 64rpx;
height: 64rpx;
display: flex;
align-items: center;
justify-content: center;
background: rgba(255, 255, 255, 0.9);
border-radius: 50%;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
.cuIcon-back {
font-size: 36rpx;
color: #333;
}
}
}
}
/* 品牌广告图片 */
.banner-container {
position: relative;
2025-03-29 16:01:43 +08:00
width: 100%;
height: 0;
padding-bottom: 75%; /* 4:3 比例 */
margin-top: v-bind('statusBarHeight + 44 + "px"');
overflow: hidden;
.banner {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
&:active {
transform: scale(1.02);
}
}
.banner-overlay {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 200rpx;
background: linear-gradient(to top, rgba(0,0,0,0.7), transparent);
}
2025-03-29 16:01:43 +08:00
}
/* 品牌信息卡片 */
2025-03-29 16:01:43 +08:00
.brand-header {
position: relative;
width: 100%;
margin-top: -150rpx;
z-index: 1;
.brand-info {
background-color: #fff;
border-radius: 42rpx 0rpx 0 0;
padding: 40rpx 32rpx;
box-shadow: 0 -10rpx 30rpx rgba(0, 0, 0, 0.05);
}
.brand-logo {
width: 100rpx;
height: 100rpx;
margin-right: 24rpx;
border-radius: 50%;
object-fit: cover;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.1);
border: 4rpx solid #fff;
transition: transform 0.3s ease;
&:active {
transform: scale(1.05);
}
}
.brand-name {
color: #0B0E26;
font-size: 36rpx;
font-weight: 600;
margin-bottom: 12rpx;
line-height: 1.4;
}
.brand-location {
display: flex;
align-items: center;
color: #5E5F60;
font-size: 24rpx;
line-height: 1.4;
.cuIcon-location {
font-size: 24rpx;
margin-right: 8rpx;
color: #19367A;
}
}
.action-buttons {
display: flex;
align-items: center;
gap: 16rpx;
.action-btn {
width: 72rpx;
height: 72rpx;
display: flex;
align-items: center;
justify-content: center;
background: #F5F5F5;
border-radius: 50%;
transition: all 0.3s ease;
&:active {
transform: scale(0.95);
}
&.active {
background: #19367A;
}
&.favor-btn {
&.active {
background: rgba(255, 77, 79, 0.1);
}
}
}
.action-icon {
width: 36rpx;
height: 36rpx;
}
}
.brand-stats {
display: flex;
justify-content: space-between;
align-items: center;
margin: 32rpx 0;
padding: 32rpx 0;
background: rgba(246, 247, 251, 0.5);
border-radius: 12rpx;
.stat-item {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
.stat-value {
font-size: 40rpx;
font-weight: 600;
color: #0B0E26;
margin-bottom: 12rpx;
line-height: 1.2;
}
.stat-label {
font-size: 24rpx;
color: #9C9BA6;
line-height: 1.4;
}
}
.stat-divider {
width: 2rpx;
height: 60rpx;
background: rgba(0, 0, 0, 0.05);
}
}
.brand-desc-container {
margin-left: 20rpx;
margin-right: 20rpx;
padding-top: 20rpx;
.brand-desc {
color: #666666;
font-size: 26rpx;
line-height: 1.8;
text-indent: 2em;
}
}
2025-03-29 16:01:43 +08:00
}
/* 标签页导航容器 */
.tab-nav-container {
position: relative;
background: #fff;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.05);
margin-bottom: 24rpx;
width: 100%;
}
2025-03-29 16:01:43 +08:00
/* 标签页导航 */
.tab-nav {
display: flex;
justify-content: space-between;
padding: 0 24rpx;
background-color: #fff;
&:after {
content: '';
position: absolute;
// bottom: -16rpx;
left: 0;
right: 0;
height: 2rpx;
background: #FFF;
}
2025-03-29 16:01:43 +08:00
.tab-item {
flex: 1;
height: 80rpx;
display: flex;
align-items: center;
justify-content: center;
font-size: 28rpx;
font-weight: 500;
color: #666666;
position: relative;
transition: all 0.3s ease;
&.active {
color: #19367A;
font-weight: 600;
&:after {
content: '';
position: absolute;
bottom: -16rpx;
left: 50%;
transform: translateX(-50%);
width: 40rpx;
height: 8rpx;
background: #19367A;
border-radius: 4rpx;
}
2025-03-29 16:01:43 +08:00
}
&:active {
opacity: 0.8;
2025-03-29 16:01:43 +08:00
}
}
}
2025-03-29 16:01:43 +08:00
/* 内容区域 */
.content-box {
margin-top: 32rpx;
box-sizing: border-box;
background-color: #fff;
border-radius: 24rpx;
box-shadow: 0 4rpx 24rpx rgba(0, 0, 0, 0.08);
/* 标签页内容区 */
.tab-content {
min-height: 600rpx;
width: 100%;
box-sizing: border-box;
2025-03-29 16:01:43 +08:00
}
/* 滚动容器 */
2025-03-29 16:01:43 +08:00
.scroll-container {
width: 100%;
height: 100%;
padding: 0;
box-sizing: border-box;
}
/* 活动列表容器 */
.activity-list {
width: 100%;
padding: 32rpx 32rpx;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
// border: 1rpx solid #FFD700;
}
/* 啤酒网格 */
.beer-grid {
width: 100%;
padding: 32rpx 32rpx;
display: flex;
flex-direction: column;
box-sizing: border-box;
}
/* 商品网格 */
.goods-grid {
width: 100%;
display: flex;
flex-wrap: wrap;
padding: 32rpx 32rpx;
gap: 24rpx;
// padding: 0 24rpx;
box-sizing: border-box;
}
/* 商品卡片 */
.goods-item {
width: calc((100% - 24rpx) / 2);
background: #FFFFFF;
border-radius: 12rpx;
overflow: hidden;
box-sizing: border-box;
box-shadow: 0 4rpx 16rpx rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.06);
}
.goods-image {
width: 100%;
height: 258rpx;
background: #F5F5F5;
transition: transform 0.3s ease;
&:active {
transform: scale(1.05);
}
}
.goods-info {
padding: 16rpx;
2025-03-29 16:01:43 +08:00
box-sizing: border-box;
}
.goods-title {
font-size: 24rpx;
color: #1A1A1A;
font-weight: 600;
margin-bottom: 12rpx;
}
.goods-price {
display: flex;
justify-content: space-between;
align-items: center;
.price-left {
display: flex;
align-items: center;
.price-num {
font-size: 32rpx;
color: #1A1A1A;
font-weight: bold;
}
.coin-icon {
color: #FFD700;
font-size: 24rpx;
margin-left: 12rpx;
}
2025-03-29 16:01:43 +08:00
}
.brand-name {
font-size: 20rpx;
color: #808080;
background: #F6F7FB;
padding: 4rpx 12rpx;
border-radius: 20rpx;
2025-03-29 16:01:43 +08:00
}
}
}
/* 加载状态 */
.loading-state {
width: 100%;
height: 100rpx;
display: flex;
align-items: center;
justify-content: center;
padding: 20rpx 0;
&.loading {
.loading-text {
display: flex;
align-items: center;
2025-03-29 16:01:43 +08:00
color: #979797;
font-size: 24rpx;
.cuIcon-loading2 {
margin-right: 8rpx;
font-size: 28rpx;
filter: drop-shadow(0 1rpx 2rpx rgba(0, 0, 0, 0.1));
animation: loading-rotate 1s linear infinite;
}
2025-03-29 16:01:43 +08:00
}
}
&.no-more {
.no-more-text {
position: relative;
color: #979797;
font-size: 24rpx;
text-shadow: 0 1rpx 2rpx rgba(0, 0, 0, 0.05);
padding: 0 30rpx;
&::before,
&::after {
content: '';
position: absolute;
top: 50%;
width: 80rpx;
height: 1px;
background: linear-gradient(to right, transparent, #979797);
}
&::before {
left: -60rpx;
}
&::after {
right: -60rpx;
transform: rotate(180deg);
}
2025-03-29 16:01:43 +08:00
}
}
}
/* 空状态 */
.empty-state {
width: 100%;
height: 400rpx;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
.empty-image {
width: 200rpx;
height: 200rpx;
margin-bottom: 20rpx;
opacity: 0.8;
}
.empty-text {
color: #979797;
font-size: 28rpx;
}
}
}
}
2025-03-29 16:01:43 +08:00
/* 文本截断 */
.text-cut {
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
2025-03-29 16:01:43 +08:00
/* 加载动画 */
.iconfont-spin {
animation: spin 1s linear infinite;
}
2025-03-29 16:01:43 +08:00
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
2025-03-29 16:01:43 +08:00
/* 加载动画 */
@keyframes loading-rotate {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
2025-03-29 16:01:43 +08:00
/* 上滑加载动画 */
@keyframes slide-in {
from {
transform: translateY(100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
2025-03-29 16:01:43 +08:00
/* 活动列表项动画 */
.activity-item {
animation: slide-in 0.3s ease-out;
}
2025-03-29 16:01:43 +08:00
/* 商品卡片动画 */
.goods-item {
animation: slide-in 0.3s ease-out;
}
2025-03-29 16:01:43 +08:00
/* 啤酒卡片动画 */
.beer-card {
animation: slide-in 0.3s ease-out;
2025-03-29 16:01:43 +08:00
}
</style>