913 lines
20 KiB
Vue
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.

<template>
<view class="page">
<!-- <view style="position: fixed;left:0px;z-index: 100;" :style="{'top': statusBaeHeight + 58 + 'px'}">
<view class="search-box" style="background: #F2F2F2;">
<input type="text" disabled placeholder="搜索酒款/酒厂" @click="toSearch">
</view>
</view> -->
<view v-if="showJoinImg && bannerJoin" class="join-box" @click="toJoin">
<image :src="bannerJoin.bannerUrl" class="img" mode="aspectFill" :lazy-load="true"></image>
</view>
<!-- 轮播 -->
<swiper v-else class="join-box"
circular
:autoplay="true"
:indicator-dots="true"
:indicator-color="'rgba(255,255,255,0.4)'"
:indicator-active-color="'#FFFFFF'"
>
<swiper-item v-for="(item,index) in homeBanner" :key="index">
<image :src="item.bannerUrl" class="img" mode="aspectFill" :lazy-load="true"></image>
</swiper-item>
</swiper>
<!-- 快捷导航 -->
<view class="bg-white"
style="border-radius: 30rpx 30rpx 12rpx 12rpx;padding-top:8rpx;position: relative;margin-top:-20rpx">
<view class="search-box hover-effect" @click="toSearch">
<view class="search-input">
<text class="cuIcon-search" style="font-size: 40rpx;color: #A2A2A2;margin-right: 24rpx;"></text>
<text style="color: #A2A2A2;">搜索酒款名称品牌名称啤酒风格</text>
</view>
<view class="searchs">
<uni-icons type="search" size="30" color="#fff"></uni-icons>
</view>
</view>
<view class="flex justify-between bg-white" style="padding: 20rpx 36rpx;">
<view class="nav-item hover-effect" v-for="(item, index) in navItems" :key="index" @click="toGo(index + 1)">
<view class="flex justify-center align-center img-box">
<image :src="'/static/nav-' + (index + 1) + '.png'" style="width: 48rpx;height: 48rpx;" :lazy-load="true"></image>
</view>
<text class="text-bold">{{item}}</text>
</view>
</view>
</view>
<!-- <commonTitle title="热门活动招募"></commonTitle> -->
<view class="section-title">
<text>热门活动招募</text>
</view>
<!-- 活动列表容器 -->
<view class="list-container">
<scroll-view
scroll-y="true"
@scrolltolower="changePage"
:scroll-anchoring="true"
>
<view class="activity-list" style="margin-top: 16rpx;">
<activity-item
v-for="(item, index) in featurePageList"
:key="index"
:item="item"
@click="handleActivityClick"
@review="toReview"
/>
</view>
<view v-if="featurePageList.length > 0" class="more-btn-box" @click="moreHotActivity">
<view class="more-btn">更多热门活动招募</view>
</view>
</scroll-view>
</view>
<!-- <view class="weixin-box zixuns">
<text>入驻助理在线服务1对1咨询使用指南~</text>
<view class="btn" @click="toAddAiad">立即添加</view>
</view> -->
<!-- <view class="weixin-box zixuns">
<text>账户正在审核中请稍等~</text>
<view class="btn" @click="toAddAiad">立即添加</view>
</view> -->
<loginPopup ref="loginRef" @loginSuccess="loginSuccess"></loginPopup>
<!-- 开屏广告 -->
<uni-popup ref="ADRef" type="center" :is-mask-click="false" maskBackgroundColor="rgba(0,0,0,0.7)" @change="handlePopupChange">
<view class="ad-container">
<swiper class="ad-swiper"
:circular="false"
:autoplay="false"
:duration="300"
:indicator-dots="true"
:indicator-color="'rgba(255,255,255,0.3)'"
:indicator-active-color="'#FFFFFF'"
@change="handleAdSwiperChange">
<swiper-item v-for="(item,index) in ADList"
:key="index"
class="ad-swiper-item"
:class="{'active': currentAdIndex === index}"
@click="handleAD(item)">
<view class="ad-image-container">
<image :src="item.bannerUrl"
class="ad-image"
mode="aspectFill"
:lazy-load="true">
</image>
</view>
</swiper-item>
</swiper>
<view class="ad-close" @click="closeAd">
<text class="cuIcon-roundclose"></text>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import {
getBannerList,
getActivities
} from '@/api/bar.js'
import {
listFeaturePage
} from '@/api/platform.js'
import loginPopup from '@/components/loginPopup.vue';
import rowBeer from '@/components/rowBeer.vue'
import ActivityItem from '@/components/ActivityItem.vue'
export default {
components: {
loginPopup,
rowBeer,
ActivityItem
},
data() {
return {
statusBaeHeight: 0,
curTag: 0,
ADList: [], // 广告弹窗
bannerJoin: null, // 认证门店banner
showJoinImg: false, // 是否显示认证门店图片
userInfo: null,
featurePageList: [], // 活动列表
homeBanner: [], //首页banner
keyword: '',
pageNum: 1,
pageSize: 10,
total: 0,
loading: false,
finished: false,
navItems: ['新酒上市', '生成酒单', '酒币换购', '关注厂牌'],
currentAdIndex: 0, // 当前广告索引
};
},
created() {
console.log('Index page created')
},
mounted() {
console.log('Index page mounted')
},
onReady() {
console.log('Index page ready')
// 确保数据已加载
if (this.featurePageList.length === 0) {
this.getActivityList()
}
},
watch: {
featurePageList: {
handler(newVal) {
console.log('featurePageList changed', newVal)
},
deep: true
}
},
onLoad() {
// setTimeout(() => {
// uni.setNavigationBarColor({
// frontColor: '#ffffff',
// backgroundColor: '#FFFFFF',
// animation: {
// duration: 400,
// timingFunc: 'easeIn'
// }
// })
// }, 500)
this.statusBaeHeight = uni.getWindowInfo.statusBarHeight
this.getBannerListFun() // 广告轮播图
uni.showShareMenu({
menus: ['shareAppMessage', 'shareTimeline']
})
// 禁用页面下拉刷新
uni.stopPullDownRefresh()
},
onShow() {
const newUserInfo = uni.getStorageSync('userInfo')
// 只在用户信息发生变化时更新状态
if (JSON.stringify(newUserInfo) !== JSON.stringify(this.userInfo)) {
this.userInfo = newUserInfo
this.showJoinImg = !this.userInfo || this.userInfo.userType === '09'
// 只在用户状态变化时重新加载数据
this.resetAndLoadData()
}
},
methods: {
loginSuccess() {
this.userInfo = uni.getStorageSync('userInfo')
this.showJoinImg = !this.userInfo || this.userInfo.userType === '09'
this.resetAndLoadData()
},
// 重置数据并重新加载
resetAndLoadData() {
this.pageNum = 1
this.featurePageList = []
this.finished = false
this.getActivityList()
},
// 获取活动列表
async getActivityList() {
if (this.loading || this.finished) return
this.loading = true
try {
const params = {
pageNum: this.pageNum,
pageSize: this.pageSize,
keyword: this.keyword,
orderType: 'latest' // 默认按最新发布排序
}
const res = await getActivities(params)
if (res.rows && res.rows.length > 0) {
// 处理剩余天数
const processedRows = res.rows.map(it => {
it.remainingDays = this.getRemainingDays(it.endDate)
return it
})
if (this.pageNum === 1) {
this.featurePageList = processedRows
} else {
this.featurePageList = [...this.featurePageList, ...processedRows]
}
this.total = res.total
this.pageNum++
// 判断是否加载完成
if (this.featurePageList.length >= this.total) {
this.finished = true
}
} else {
if (this.pageNum === 1) {
this.featurePageList = []
}
this.finished = true
}
} catch (error) {
console.error('获取活动列表失败:', error)
uni.showToast({
title: '加载失败',
icon: 'none'
})
} finally {
this.loading = false
}
},
// 计算剩余天数
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
},
// 加载更多
changePage() {
if (!this.loading && !this.finished) {
this.getActivityList()
}
},
// 更多热门活动
moreHotActivity() {
uni.navigateTo({
url: '/pages/activityList/activityList'
})
},
// 处理活动点击
handleActivityClick(item) {
uni.navigateTo({
url: `/pagesActivity/activityDetail?id=${item.id}`
})
},
// 跳转酒评页
toReview(it) {
const token = uni.getStorageSync('token')
if (!token) {
this.$refs.loginRef.show()
return
}
uni.navigateTo({
url: "/pages/index/review?beerId=" + it.id
})
},
// 查询广告弹窗 banner列表
getBannerListFun() {
this.ADList = []
this.homeBanner = []
this.bannerJoin = null
getBannerList().then(res => {
if (!res.data || !Array.isArray(res.data)) return
res.data.forEach(it => {
if (it.bannerType === 'homeAD') { // 开屏广告
this.ADList.push(it)
} else if (it.bannerType === 'homeJoin') { // 认证门店
this.bannerJoin = it
} else if (it.bannerType === 'homeBanner') { // 首页banner
this.homeBanner.push(it)
}
})
// 检查是否需要显示开屏广告
const lastShowTime = uni.getStorageSync('lastShowHomeADTime')
const currentTime = new Date().getTime()
// 如果从未显示过或者距离上次显示超过24小时
if (!lastShowTime || (currentTime - lastShowTime > 24 * 60 * 60 * 1000)) {
if (this.ADList.length > 0) {
this.$refs.ADRef.open()
}
}
}).catch(err => {
console.error('获取banner列表失败', err)
})
},
closeAd() {
// 记录广告显示时间
uni.setStorageSync('lastShowHomeADTime', new Date().getTime())
uni.setTabBarStyle({
backgroundColor: '#ffffff'
})
this.$refs.ADRef.close()
},
handleAD(item) {
if (!item || !item.bannerLink) return
this.closeAd()
// 处理不同类型的链接
if (item.bannerLink.startsWith('/')) {
// 内部页面跳转
uni.navigateTo({
url: item.bannerLink,
fail: () => {
// 如果普通跳转失败尝试switchTab
uni.switchTab({
url: item.bannerLink,
fail: (err) => {
console.error('页面跳转失败:', err)
uni.showToast({
title: '页面跳转失败',
icon: 'none'
})
}
})
}
})
} else if (item.bannerLink.startsWith('http')) {
// 外部链接可以使用web-view页面打开
uni.navigateTo({
url: `/pages/webview/webview?url=${encodeURIComponent(item.bannerLink)}`
})
}
},
// 立即认证门店
toJoin() {
if (!this.bannerJoin || !this.bannerJoin.bannerLink) return
// 处理不同类型的链接
if (this.bannerJoin.bannerLink.startsWith('/')) {
// 内部页面跳转
uni.navigateTo({
url: this.bannerJoin.bannerLink,
fail: () => {
// 如果普通跳转失败尝试switchTab
uni.switchTab({
url: this.bannerJoin.bannerLink,
fail: (err) => {
console.error('页面跳转失败:', err)
uni.showToast({
title: '页面跳转失败',
icon: 'none'
})
}
})
}
})
} else if (this.bannerJoin.bannerLink.startsWith('http')) {
// 外部链接使用web-view页面打开
uni.navigateTo({
url: `/pages/webview/webview?url=${encodeURIComponent(this.bannerJoin.bannerLink)}`
})
}
},
// 搜索
toSearch() {
uni.navigateTo({
url: '/pagesActivity/homeSearch'
})
},
// 导航跳转
toGo(index) {
switch(index) {
case 1: // 新酒上市
uni.navigateTo({
url: '/pages/index/newBeer'
})
break;
case 2: // 生成酒单
uni.navigateTo({
url: '/pagesActivity/winelist'
})
break;
case 3: // 酒币换购
uni.navigateTo({
url: '/pagesCoin/beerCoin'
})
break;
case 4: // 关注厂牌
uni.navigateTo({
url: '/pagesMy/myAttention'
})
break;
}
},
// 处理广告轮播切换
handleAdSwiperChange(e) {
this.currentAdIndex = e.detail.current
},
// 处理弹窗状态变化
handlePopupChange(e) {
if (!e.show) {
this.closeAd()
}
},
// 跳转到生成酒单页面
toBeerList() {
uni.switchTab({
url: '/pages/index/beerList'
})
},
// 跳转到酒币兑换页面
toBeerCoin() {
uni.switchTab({
url: '/pages/index/beerCoin'
})
},
// 跳转到我的关注页面
toMyAttention() {
uni.switchTab({
url: '/pages/index/myAttention'
})
}
}
}
</script>
<style lang="scss" scoped>
/deep/.uni-popup {
z-index: 1025;
}
.page {
background: #F9F9F9;
min-height: 100vh;
display: flex;
flex-direction: column;
font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Helvetica Neue", Roboto, "Segoe UI", "Microsoft YaHei", sans-serif;
.join-box {
width: 100%;
height: 562rpx;
background: #f5f5f5;
position: relative;
overflow: hidden;
.img {
width: 100%;
height: 100%;
object-fit: cover;
}
/deep/ .uni-swiper-dots {
bottom: 20rpx;
.uni-swiper-dot {
width: 12rpx;
height: 12rpx;
border-radius: 6rpx;
margin: 0 6rpx;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.4);
&.uni-swiper-dot-active {
width: 28rpx;
background-color: #FFFFFF;
box-shadow: 0 2rpx 8rpx rgba(255, 255, 255, 0.3);
}
}
}
}
}
.search-box {
border-radius: 24rpx;
width: 700rpx;
height: 80rpx;
background-color: #F9F9F9;
display: flex;
align-items: center;
padding: 32rpx 0;
margin: 26rpx auto;
box-sizing: border-box;
box-shadow: 0rpx 1rpx 3rpx 0rpx rgba(0, 0, 0, 0.1);
.search-input {
flex: 1;
display: flex;
align-items: center;
padding: 0 24rpx;
}
.searchs{
background: #D42E78;
width: 80rpx;
height: 80rpx;
border-radius: 0 24rpx 24rpx 0;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0rpx 1rpx 3rpx 0rpx rgba(0, 0, 0, 0.1);
}
}
.section-title {
margin: 46rpx 24rpx 32rpx 24rpx;
font-size: 40rpx;
font-weight: bold;
color: #030303;
}
.list-container {
flex: 1;
display: flex;
flex-direction: column;
min-height: 200rpx;
position: relative;
z-index: 0;
scroll-view {
flex: 1;
}
.activity-list {
padding: 0 32rpx;
opacity: 1;
transition: opacity 0.3s ease;
&.loading {
opacity: 0.6;
}
}
.more-btn-box {
width: 92%;
height: 88rpx;
margin: 32rpx auto;
background: linear-gradient(135deg, #19367A, #2C4C99);
border-radius: 12rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 4rpx 16rpx rgba(25, 54, 122, 0.2);
transition: all 0.3s ease;
&:active {
transform: scale(0.98);
box-shadow: 0 2rpx 8rpx rgba(25, 54, 122, 0.1);
}
.more-btn {
font-size: 28rpx;
font-weight: 600;
letter-spacing: 2rpx;
color: #FFFFFF;
}
}
}
.join-box {
// margin: 20rpx 0;
// border-radius: 30rpx;
box-sizing: border-box;
// border: 1.5px solid #F2F2F2;
// padding: 34rpx 26rpx;
// height: 450rpx;
// height: 1130rpx;
height: 562rpx;
display: flex;
flex-direction: column;
justify-content: space-around;
.btn {
width: 582rpx;
height: 68rpx;
border-radius: 24rpx;
text-align: center;
line-height: 68rpx;
margin: 0 auto;
background: #D42E78;
}
.img {
width: 100%;
height: 100%;
}
}
.swiper {
margin-bottom: 20rpx;
height: 400rpx;
}
// 快捷导航
.nav-item {
text-align: center;
color: #0B0E26;
.img-box {
width: 146rpx;
height: 146rpx;
background: #F9F9F9;
border-radius: 50%;
margin-bottom: 18rpx;
box-shadow: 0rpx 1rpx 3rpx 0rpx rgba(0, 0, 0, 0.1);
}
}
.quickNav-box {
border-radius: 20rpx;
background: #FFFFFF;
width: 100%;
padding: 32rpx 24rpx;
height: 490rpx;
box-sizing: border-box;
.left {
height: 416rpx;
width: 352rpx;
// width: 47%;
border-radius: 20rpx;
margin-right: 22rpx;
}
.right {
height: 196rpx;
// width: 326rpx;
width: 100%;
margin-bottom: 22rpx;
border-radius: 20rpx;
}
}
.goods-box {
border-radius: 30rpx;
background: rgba(255, 255, 255, 0.2);
box-sizing: border-box;
border: 1px solid #F2F2F2;
box-shadow: 0px 5.47px 43.78px 0px rgba(0, 0, 0, 0.05);
display: flex;
padding: 16rpx 32rpx;
margin: 20rpx 32rpx 0;
.cover {
width: 208rpx;
height: 300rpx;
border-radius: 30rpx;
margin-right: 14rpx;
}
}
.tag {
background-color: transparent;
border-radius: 12rpx;
padding: 12rpx 20rpx;
border: 1px solid #9D9D9D;
;
margin-right: 24rpx;
margin-bottom: 50rpx;
}
.active-tag {
background-color: #FEE034;
font-weight: bold;
border: 1px solid #FEE034;
}
.title-box {
padding: 24rpx 32rpx;
margin-bottom: 28rpx;
box-sizing: border-box;
.title {
font-size: 32rpx;
font-weight: bold;
color: #1E2019;
line-height: 130%;
}
.sub {
font-size: 20rpx;
color: #9D9D9D;
}
}
.zixuns {
padding: 0 34rpx 0 20rpx;
background: rgba(0, 0, 0, 0.6);
}
.bg-white {
background: #FFFFFF;
border-radius: 30rpx 30rpx 12rpx 12rpx;
padding-top: 8rpx;
position: relative;
transform: translateY(-20rpx);
z-index: 1;
.search-box {
margin: 24rpx 32rpx;
}
}
.activity-item {
display: block;
}
.hover-effect {
transition: all 0.2s ease;
&:active {
transform: scale(0.96);
opacity: 0.8;
}
}
.search-box {
// ... existing code ...
&:active {
transform: scale(0.98);
opacity: 0.9;
}
}
.nav-item {
// ... existing code ...
&:active {
transform: scale(0.95);
opacity: 0.8;
}
}
.more-btn-box {
// ... existing code ...
&:active {
transform: scale(0.98);
opacity: 0.9;
}
}
.activity-item {
// ... existing code ...
&:active {
transform: scale(0.98);
opacity: 0.9;
}
}
// 添加图片加载优化相关样式
.img {
width: 100%;
height: 100%;
will-change: transform;
backface-visibility: hidden;
transform: translateZ(0);
}
// 添加骨架屏样式
.skeleton {
background: linear-gradient(90deg, #f2f2f2 25%, #e6e6e6 37%, #f2f2f2 63%);
background-size: 400% 100%;
animation: skeleton-loading 1.4s ease infinite;
}
@keyframes skeleton-loading {
0% {
background-position: 100% 50%;
}
100% {
background-position: 0 50%;
}
}
.ad-container {
position: relative;
width: 750rpx;
height: 70vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
animation: fadeIn 0.3s ease;
padding: 0 40rpx;
box-sizing: border-box;
}
.ad-swiper {
width: 100%;
height: 85%;
overflow: visible;
}
.ad-swiper-item {
box-sizing: border-box;
transition: all 0.3s ease;
transform: scale(0.85);
opacity: 0.6;
&.active {
transform: scale(1);
opacity: 1;
}
}
.ad-image-container {
width: 100%;
height: 100%;
position: relative;
border-radius: 30rpx;
overflow: hidden;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.15);
}
.ad-image {
width: 100%;
height: 100%;
border-radius: 30rpx;
will-change: transform;
backface-visibility: hidden;
transform: translateZ(0);
}
.ad-close {
margin-top: 40rpx;
width: 72rpx;
height: 72rpx;
display: flex;
justify-content: center;
align-items: center;
background: rgba(255, 255, 255, 0.15);
border-radius: 50%;
backdrop-filter: blur(10px);
transition: all 0.3s ease;
.cuIcon-roundclose {
font-size: 44rpx;
color: #FFFFFF;
text-shadow: 0 2rpx 4rpx rgba(0, 0, 0, 0.2);
}
&:active {
transform: scale(0.9);
opacity: 0.8;
background: rgba(255, 255, 255, 0.25);
}
}
/deep/ .uni-swiper-dots {
bottom: -20rpx !important;
.uni-swiper-dot {
width: 12rpx !important;
height: 12rpx !important;
border-radius: 6rpx !important;
margin: 0 6rpx !important;
transition: all 0.3s ease !important;
background: rgba(255, 255, 255, 0.3) !important;
&.uni-swiper-dot-active {
width: 28rpx !important;
background-color: #FFFFFF !important;
box-shadow: 0 2rpx 8rpx rgba(255, 255, 255, 0.3);
}
}
}
// 添加过渡效果
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter, .fade-leave-to {
opacity: 0;
}
</style>