467 lines
12 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 class="page-content flex-col">
<!-- 筛选导航 -->
<view class="filter-tabs">
<view class="tabs-content">
<view
class="tab-item"
:class="{'active-tag': queryForm.orderType == 'latest'}"
@click="changeOrder('latest')"
>最新发布</view>
<view
class="tab-item"
:class="{'active-tag': queryForm.orderType == 'popularity'}"
@click="changeOrder('popularity')"
>人气排名</view>
<view class="brand-filter" :class="{ active: selectedBrand !== null }" @click="showBrandFilter">
<text>筛选品牌</text>
<image :src="'/static/icons/filter.svg'" mode="aspectFit" class="filter-icon"></image>
</view>
</view>
</view>
<!-- 列表内容区域 -->
<view class="list-container">
<scroll-view
style="height: 100%;"
scroll-y="true"
@scrolltolower="changePage"
refresher-enabled="true"
:refresher-triggered="isRefreshing"
@refresherrefresh="onRefresh"
>
<view class="activity-item flex" v-for="(it, index) in activeList" :key="index" @click="toDetail(it)">
<view class="left flex flex-col justify-between align-center">
<image :src="it.brandLogo" style="width: 140rpx;height: 140rpx;"></image>
<text>活动状态</text>
<view v-if="it.stage == 0">未开始</view>
<view v-if="it.stage == 2">已结束</view>
<view v-if="it.stage == 3">已结束</view>
<view v-if="it.stage == 4">活动停止</view>
<view v-if="it.stage == 1" class="margin-bottom-xs" style="color: #9E9E9E;font-size: 24rpx;">招募即将结束</view>
<view v-if="it.stage == 1">
<text style="font-size: 72rpx; color: #DE3C4B;">{{it.remainingDays}}</text>
</view>
</view>
<view class="right">
<view class="title">{{ it.breweryName }}</view>
<view class="sub">时间首次扫码开始累计 <text style="color:#DE3C4B">{{it.duration}}天内</text></view>
<view class="sub">目标全系列酒款累积扫码 {{ it.activityTarget}}</view>
<scroll-view v-if="it.beers" scroll-x="true" class="scroll-img">
<view class="beer-box" v-for="(it, index) in it.beers" :key="index" @click="toReview(it)">
<image v-if="it.cover" :src="it.cover" class="cover"></image>
</view>
</scroll-view>
<view class="flex align-center">
<text v-if="it.activityRewardType == 2 || (it.activityRewardType == 1 && it.activityRewardGoods)" class="zeng"></text>
<text v-if="it.activityRewardType == 1 && it.activityRewardGoods" style="color: #0B0E26;font-size: 24rpx;">{{it.activityRewardGoods.goodsName}} * {{it.activityRewardCount}}</text>
<text v-if="it.activityRewardType == 2" style="color: #0B0E26;font-size: 24rpx;">啤酒币 * {{it.activityRewardCount}}</text>
</view>
</view>
</view>
<view class="cu-load" :class="loading?'loading': activeList.length == total ? 'over' :'more'"></view>
</scroll-view>
</view>
<loginPopup ref="loginRef"></loginPopup>
<!-- 品牌筛选组件 -->
<brand-filter ref="brandFilterRef" @confirm="onBrandFilterConfirm"></brand-filter>
</view>
</view>
</template>
<script>
import {
getActivities
} from '@/api/bar.js'
import loginPopup from '@/components/loginPopup.vue'
import brandFilter from '@/components/brandFilter.vue'
export default {
components: {
loginPopup,
brandFilter
},
data() {
return {
activeList: [], // 活动列表
loading: false,
isRefreshing: false,
queryForm: {
pageNum: 1,
pageSize: 5,
orderType: 'latest',
},
total: 0,
isFilterActive: false,
userLocation: null,
isLocationReady: false, // 位置信息是否已获取
originalList: [], // 存储未经位置筛选的列表
selectedBrand: null, // 选中的品牌ID
};
},
onLoad() {
// 先获取活动列表
this.getActivitiesFun();
// 同时异步获取位置信息
this.getUserLocation();
},
methods: {
// 获取用户位置
getUserLocation() {
uni.getLocation({
type: 'gcj02',
success: (res) => {
this.userLocation = {
latitude: res.latitude,
longitude: res.longitude
};
this.isLocationReady = true;
// 位置信息获取成功后,重新筛选列表
this.filterListByLocation();
},
fail: (err) => {
console.error('获取位置失败:', err);
this.isLocationReady = true;
uni.showToast({
title: '未获取到位置信息,将显示所有活动',
icon: 'none',
duration: 2000
});
}
});
},
// 根据位置信息筛选列表
filterListByLocation() {
if (this.originalList.length > 0) {
this.activeList = this.originalList.filter(item => this.isActivityInUserCity(item.city));
}
},
// 检查活动是否在用户所在城市
isActivityInUserCity(activityCity) {
if (!this.userLocation) return false;
try {
const cityList = JSON.parse(activityCity);
// 这里需要和获取到的用户城市信息进行比对
return true; // 临时返回true需要实际实现
} catch (e) {
return false;
}
},
// 切换排序
changeOrder(type) {
// 如果点击当前激活的排序方式,不做处理
if (this.queryForm.orderType === type) return;
// 切换排序方式
this.queryForm.orderType = type;
// 重置分页
this.queryForm.pageNum = 1;
this.activeList = [];
// 重新获取数据
this.getActivitiesFun();
},
// 分页加载
changePage() {
if (this.activeList.length < this.total) {
this.queryForm.pageNum++;
this.getActivitiesFun();
}
},
// 跳转详情
toDetail(item) {
uni.navigateTo({
url: "/pagesActivity/activityDetail?id=" + item.id
});
},
// 跳转酒评
toReview(it) {
uni.navigateTo({
url: "/pages/index/review?beerId=" + it.id
});
},
// 获取活动列表
getActivitiesFun() {
this.loading = true;
const params = {
pageNum: this.queryForm.pageNum,
pageSize: this.queryForm.pageSize
};
// 添加品牌筛选
if (this.selectedBrand) {
params.breweryId = this.selectedBrand;
} else {
// 只有在没有品牌筛选时,才应用排序
params.orderBy = this.queryForm.orderType === 'latest' ? 'start_date' : 'popularity';
params.order = 'desc';
}
getActivities(params).then(res => {
this.total = res.total;
if(res.rows && res.rows.length > 0) {
let arr = res.rows.map(it => {
it.remainingDays = this.getRemainingDays(it.endDate);
return it;
});
// 过滤活动状态:不显示已结束(2,3)、活动停止(4)、未开始(0)的活动
arr = arr.filter(item => item.stage === 1);
// 如果有品牌筛选,确保只显示选中品牌的活动
if (this.selectedBrand) {
arr = arr.filter(item => item.breweryId === this.selectedBrand);
}
// 保存未经位置筛选的列表
this.originalList = arr;
// 如果位置信息已准备好,进行位置筛选
if (this.isLocationReady && this.userLocation) {
arr = arr.filter(item => this.isActivityInUserCity(item.city));
}
// 更新显示列表
if (this.queryForm.pageNum === 1) {
this.activeList = arr;
} else {
this.activeList = [...this.activeList, ...arr];
}
} else {
if (this.queryForm.pageNum === 1) {
this.activeList = [];
this.originalList = [];
}
}
this.loading = false;
}).catch(err => {
console.error('获取活动列表失败:', err);
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;
},
// 显示品牌筛选
showBrandFilter() {
// 如果还没有数据,先获取数据
if (!this.originalList || this.originalList.length === 0) {
this.queryForm.pageNum = 1;
this.getActivitiesFun().then(() => {
this.$refs.brandFilterRef.extractBrandsFromList(this.originalList);
this.$refs.brandFilterRef.open();
});
} else {
this.$refs.brandFilterRef.extractBrandsFromList(this.originalList);
this.$refs.brandFilterRef.open();
}
},
// 品牌筛选确认
onBrandFilterConfirm(result) {
this.selectedBrand = result.id;
this.queryForm.pageNum = 1;
this.activeList = [];
this.getActivitiesFun();
},
// 添加下拉刷新方法
onRefresh() {
this.isRefreshing = true;
// 重置分页参数
this.queryForm.pageNum = 1;
this.activeList = [];
// 重新获取数据
this.getActivitiesFun();
}
}
}
</script>
<style lang="scss" scoped>
.page {
min-height: 100vh;
background: #F9F9F9;
}
.filter-tabs {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 99;
background: #FFFFFF;
// border-bottom: 1rpx solid #F5F5F5
.tabs-content {
display: flex;
align-items: center;
padding: 20rpx 32rpx;
height: 112rpx;
width: 100%;
.tab-item {
width: 144rpx;
height: 64rpx;
line-height: 64rpx;
border-radius: 12rpx;
background: #F9F9F9;
margin-right: 16rpx;
font-size: 24rpx;
font-weight: 500;
text-align: center;
&.active-tag {
// 选中状态的样式
color: #FFF;
background: #D42E78;
}
}
.brand-filter {
margin-left: auto;
display: flex;
align-items: center;
justify-content: center;
height: 64rpx;
min-width: 144rpx; // 最小宽度
padding: 0 24rpx; // 左右内边距
border-radius: 12rpx;
background: #FFFFFF;
border: 1rpx solid #D42E78;
transition: all 0.3s; // 添加过渡效果
text {
color: #D42E78;
font-size: 24rpx;
font-weight: 500;
margin-right: 8rpx; // 文字和图标的间距
}
.filter-icon {
width: 32rpx;
height: 32rpx;
}
// 激活状态
&.active {
background: #D42E78;
border-color: #D42E78;
text {
color: #FFFFFF;
}
.filter-icon {
filter: brightness(0) invert(1); // 将图标改为白色
}
}
}
}
}
.list-container {
margin-top: 104rpx; // 筛选栏高度
padding: 24rpx 32rpx;
}
.activity-item {
border-radius: 20rpx;
background: #FDFDFD;
box-sizing: border-box;
border: 1px solid #F2F2F2;
width: 702rpx;
margin-bottom: 32rpx;
.left {
padding: 24rpx 20rpx;
border-radius: 20rpx;
background: #FFFFFF;
box-sizing: border-box;
border: 1px solid #EFEDE9;
width: 180rpx;
margin-top: -10rpx;
margin-bottom: -10rpx;
}
.right {
padding: 20rpx;
flex:1;
.title {
font-family: Source Han Sans;
font-size: 28rpx;
font-weight: bold;
line-height: 30rpx;
color: #0B0E26;
margin-bottom: 20rpx;
}
.sub {
font-family: Source Han Sans;
font-size: 24rpx;
font-weight: 500;
line-height: 30rpx;
color: #0B0E26;
margin-bottom: 16rpx;
}
.scroll-img {
width: 500rpx;
display: flex;
flex-direction: row;
white-space: nowrap;
height: 144rpx;
margin-bottom: 20rpx;
.beer-box {
width: 100rpx;
background: #FFFFFF;
margin-right: 20rpx;
box-sizing: border-box;
display: inline-block;
// &:nth-child(1) {
// margin-left: 32rpx;
// }
.cover {
width: 100rpx;
height: 144rpx;
border-radius: 10rpx;
}
}
}
.zeng {
font-family: Source Han Sans;
font-size: 20rpx;
font-weight: bold;
line-height: normal;
text-align: center;
color: #0B0E26;
padding: 8rpx 12rpx;
border-radius: 10rpx;
background: #FEE034;
margin-right: 20rpx;
}
}
}
</style>