654 lines
18 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="activitypage">
<!-- 已登录用户显示内容 -->
<template v-if="userInfo">
<!-- 主导航栏 -->
<view class="main-nav">
<view class="nav-item" :class="{'nav-active': tabCur == 0}" @tap="tabSelect" :data-id="0">
累计活动
<view class="nav-line" v-if="tabCur == 0"></view>
</view>
<view class="nav-item" :class="{'nav-active': tabCur == 1}" @tap="tabSelect" :data-id="1">
啤酒币换购
<view class="nav-line" v-if="tabCur == 1"></view>
</view>
</view>
<!-- 状态标签栏 -->
<scroll-view scroll-x class="status-nav" :scroll-left="0">
<view class="status-nav-content">
<template v-if="tabCur == 0">
<view class="status-item" :class="{'status-active': curTag == 0}" @tap="changeTag(0)">累计中</view>
<view class="status-item" :class="{'status-active': curTag == 1}" @tap="changeTag(1)">待兑付</view>
<view class="status-item" :class="{'status-active': curTag == 2}" @tap="changeTag(2)">已兑付</view>
<view class="status-item" :class="{'status-active': curTag == 3}" @tap="changeTag(3)">已完成</view>
</template>
<template v-else>
<view class="status-item" :class="{'status-active': curCoinTag == 0}" @tap="changeCoinTag(0)">全部</view>
<view class="status-item" :class="{'status-active': curCoinTag == 1}" @tap="changeCoinTag(1)">待发货</view>
<view class="status-item" :class="{'status-active': curCoinTag == 2}" @tap="changeCoinTag(2)">已收货</view>
<view class="status-item" :class="{'status-active': curCoinTag == 3}" @tap="changeCoinTag(3)">已完成</view>
</template>
</view>
</scroll-view>
<view class="bg-white flex-col" style="height: 100%;">
<!-- 累积活动列表 -->
<scroll-view v-if="tabCur == 0" scroll-y
style="padding: 16rpx 28rpx 0;background-color: #F2F2F2;overflow-y: auto;flex:1"
@scrolltolower="changePage">
<!-- 活动列表项 -->
<view class="activity-item flex" v-for="(it, index) in myJoinList" :key="index" @click="toInfo(it)">
<!-- 左侧区域品牌logo和达成进度 -->
<view class="left flex flex-col justify-between align-center">
<!-- 品牌logo固定尺寸140x140 -->
<image :src="it.brandLogo" style="width: 140rpx;height: 140rpx;border-radius: 6rpx;">
</image>
<!-- 达成进度提示文字 -->
<view style="color: #606060;font-size: 24rpx;font-weight: bold;white-space: nowrap;">距离达成还剩</view>
<!-- 剩余数量/达标状态根据不同状态显示不同内容 -->
<view>
<!-- 累计中remainingBeerCount > 0 -->
<template v-if="it.remainingBeerCount > 0">
<text style="font-family: Roboto;font-size: 24rpx;font-weight: normal;line-height: 16rpx; text-align: center;letter-spacing: normal;color: #0B0E26;">{{ it.remainingBeerCount }}</text>
<text style="font-size: 24rpx;color: #0B0E26;"></text>
</template>
<!-- 待兑付remainingBeerCount <= 0 且未兑付 -->
<template v-else-if="it.remainingBeerCount <= 0 && !it.barAwardStatus">
<text style="font-family: Roboto;font-size: 24rpx; color: #19367A;font-weight: bold;line-height: 130%;text-align: center;letter-spacing: normal;">待兑付</text>
</template>
<!-- 已兑付厂家已兑付状态 -->
<template v-else-if="it.barAwardStatus">
<text style="font-family: Roboto;font-size: 24rpx; color: #19367A;font-weight: bold;line-height: 130%;text-align: center;letter-spacing: normal;">已兑付</text>
</template>
<!-- 已完成活动已完成状态 -->
<template v-else-if="it.activityStatus === 'COMPLETED'">
<text style="font-family: Roboto;font-size: 24rpx; color: #19367A;font-weight: bold;line-height: 130%;text-align: center;letter-spacing: normal;">已完成</text>
</template>
</view>
</view>
<!-- 右侧区域活动详细信息 -->
<view class="right">
<!-- 活动名称 -->
<view class="title">{{ it.activityName }}</view>
<!-- 活动时间首次扫码开始计算 -->
<view class="sub">时间首次扫码开始累计 <text style="color:#19367A">{{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 class="zeng"></text>
<!-- 实物奖励type=1 -->
<text v-if="it.activityRewardType == 1 && it.activityRewardGoods"
style="color: #0B0E26;font-size: 24rpx;">{{it.activityRewardGoods.goodsName}} * {{it.activityRewardCount}}</text>
<!-- 啤酒币奖励type=2 -->
<text v-if="it.activityRewardType == 2"
style="color: #0B0E26;font-size: 24rpx;">啤酒币 * {{it.activityRewardCount}}</text>
<!-- 奖励发放状态 -->
<text v-if="it.barAwardStatus"
style="color: #0B0E26;font-size: 24rpx;">已发放</text>
</view>
</view>
</view>
<!-- 列表加载状态 -->
<view class="cu-load" :class="'over'"></view>
</scroll-view>
<!-- 啤酒币换购列表 -->
<scroll-view v-if="tabCur == 1" scroll-y
style="padding: 16rpx 28rpx 0;background-color: #F2F2F2;overflow-y: auto;flex:1"
@scrolltolower="changePageCoin">
<!-- 兑换订单列表 -->
<view class="coin-item" v-for="(it, index) in myExchangeOrder" :key="index" @click="toOrderInfo(it)">
<view class="flex justify-between" style="margin-bottom: 16rpx;">
<text style="color: #0B0E26;font-size: 28rpx;">
<image src="@/static/beerCoin.png" style="width: 24rpx;height: 24rpx;margin-right: 16rpx;"></image>
啤酒币兑换</text>
<text style="color: #5E5F60;font-size: 24rpx;">已完成</text>
</view>
<view class="flex justify-between">
<image :src="it.goodsCover" class="coverImg"></image>
<view class="flex justify-between flex-col flex-1" style="padding: 24rpx 0">
<text class="title word-all">{{ it.goodsName }}</text>
</view>
<view class="flex flex-col justify-center align-end">
<view class="margin-bottom">
<text class="num">{{ it.beerCoinNum}}</text>
<text class="cuIcon-rechargefill"
style="color:rgba(255, 213, 43, 1);font-size: 36rpx;margin-left: 6rpx;"></text>
</view>
<text style="color: #5E5F60;font-size: 20rpx;">{{it.redeemNum}}</text>
</view>
</view>
</view>
<view class="cu-load" :class="orderTotal == myExchangeOrder.length ? 'over': 'more'"></view>
</scroll-view>
</view>
</template>
<!-- 未登录用户显示内容 -->
<template v-else>
<view class="flex justify-center align-center" style="height: 100vh;background-color: #FDFDFD;">
<view class="flex-direction flex align-center">
<text class="text-lg margin-top" style="color: #3D3D3D;font-weight: 600;;">暂无法查看信息</text>
<text class="margin-top" style="color: #979797;font-size: 28rpx;">您还没有登录请登录后查看信息</text>
<button class="cu-btn margin-top" style="width: 306rpx;height: 88rpx;background-color: #4E63E0;font-family: Roboto;font-size: rpx;font-weight: 500;line-height: 20rpx;color: #FFFFFF;" @click="toLogin">
<image src="@/static/send-2.svg" style="width: 48rpx;height: 48rpx;margin-right: 16rpx;"></image>
登录/认证</button>
</view>
</view>
</template>
<!-- 登录弹窗组件 -->
<loginPopup ref="loginRef" @loginSuccess="loginSuccess"></loginPopup>
</view>
</template>
<script>
import loginPopup from '@/components/loginPopup.vue';
import { myJoinListApi, getMyExchangeOrder } from "@/api/user.js"
export default {
components: {
loginPopup
},
data() {
return {
loading: true,
userInfo: null, // 用户信息
tabCur: 0, // 当前选中的标签页
curTag: 0, // 累积活动当前选中的标签
curCoinTag: 0, // 啤酒币换购当前选中的标签
myJoinList: [], // 我参与的活动列表
queryForm: {
status: 1, // 活动状态
pageNum: 1,
pageSize: 10
},
total: 0, // 活动总数
myExchangeOrder:[], // 兑换订单列表
orderQuery: {
pageNum: 1,
pageSize: 10
},
orderTotal: 0, // 订单总数
isLoading: false, // 是否正在加载数据
isRefreshing: false, // 是否正在刷新
};
},
onLoad() {
this.initData()
},
onShow() {
this.checkUserInfo()
},
methods: {
// 初始化数据
async initData() {
try {
this.userInfo = uni.getStorageSync('userInfo')
if (this.userInfo) {
this.loading = false
await this.getMyJoinList()
}
} catch (error) {
console.error('初始化数据失败:', error)
uni.showToast({
title: '加载失败',
icon: 'none'
})
}
},
// 检查用户信息变化
async checkUserInfo() {
try {
const newUserInfo = uni.getStorageSync('userInfo')
if (newUserInfo !== this.userInfo) {
this.userInfo = newUserInfo
if (this.userInfo) {
this.loading = false
await this.getMyJoinList()
}
}
} catch (error) {
console.error('检查用户信息失败:', error)
}
},
// 登录成功回调
async loginSuccess() {
try {
this.userInfo = uni.getStorageSync('userInfo')
if (this.userInfo) {
this.loading = false
await this.getMyJoinList()
}
} catch (error) {
console.error('登录成功处理失败:', error)
uni.showToast({
title: '登录失败',
icon: 'none'
})
}
},
// 获取我的兑换订单
async getMyExchangeOrderFun() {
if (this.isLoading) return
try {
this.isLoading = true
const res = await getMyExchangeOrder(this.orderQuery)
if (res && res.rows) {
this.orderTotal = res.total || 0
if (this.orderQuery.pageNum === 1) {
this.myExchangeOrder = res.rows
} else {
this.myExchangeOrder = [...this.myExchangeOrder, ...res.rows]
}
}
} catch (error) {
console.error('获取兑换订单失败:', error)
uni.showToast({
title: '获取订单失败',
icon: 'none'
})
} finally {
this.isLoading = false
}
},
// 切换标签页
async tabSelect(e) {
const id = e.currentTarget.dataset.id
if (this.tabCur === id) return
this.tabCur = id
if (this.tabCur == 0) {
this.myJoinList = []
this.queryForm.pageNum = 1
await this.getMyJoinList()
} else {
this.myExchangeOrder = []
this.orderQuery.pageNum = 1
await this.getMyExchangeOrderFun()
}
},
// 获取我参与的活动列表
async getMyJoinList() {
if (this.isLoading) return
try {
this.isLoading = true
const res = await myJoinListApi(this.queryForm)
if (res && res.data) {
this.total = res.data.total || 0
let activities = []
// 处理品牌活动
if (res.data.activities && res.data.activities.length > 0) {
activities = activities.concat(res.data.activities)
}
// 处理平台活动
if (res.data.platformActivities && res.data.platformActivities.length > 0) {
activities = activities.concat(res.data.platformActivities)
}
// 根据当前选中的状态标签过滤活动
const filteredActivities = activities.filter(activity => {
switch(this.curTag) {
case 0: // 累计中
return activity.remainingBeerCount > 0
case 1: // 待兑付
return activity.remainingBeerCount <= 0 && !activity.barAwardStatus
case 2: // 已兑付
return activity.barAwardStatus
case 3: // 已完成
return activity.activityStatus === 'COMPLETED'
default:
return true
}
})
if (this.queryForm.pageNum === 1) {
this.myJoinList = filteredActivities
} else {
this.myJoinList = [...this.myJoinList, ...filteredActivities]
}
}
} catch (error) {
console.error('获取活动列表失败:', error)
uni.showToast({
title: '获取活动列表失败',
icon: 'none'
})
} finally {
this.isLoading = false
}
},
// 加载更多活动
async changePage() {
if (this.myJoinList.length < this.total && !this.isLoading) {
this.queryForm.pageNum++
await this.getMyJoinList()
}
},
// 跳转到活动详情
toInfo(it) {
if (!it.batchId) return
uni.navigateTo({
url: '/pagesActivity/myActivityDetail?batchId=' + it.batchId
})
},
// 跳转到订单详情
toOrderInfo(it) {
if (!it.id || !it.goodsId) return
uni.navigateTo({
url: '/pagesCoin/orderInfo?orderId=' + it.id + '&goodsId=' + it.goodsId
})
},
// 切换活动状态标签
async changeTag(key) {
if (this.curTag === key) return
this.curTag = key
this.queryForm.pageNum = 1
this.myJoinList = []
// 设置查询状态
switch(key) {
case 0: // 累计中
this.queryForm.status = 'ACCUMULATING'
break
case 1: // 待兑付
this.queryForm.status = 'PENDING_PAYMENT'
break
case 2: // 已兑付
this.queryForm.status = 'PAID'
break
case 3: // 已完成
this.queryForm.status = 'COMPLETED'
break
default:
delete this.queryForm.status
}
await this.getMyJoinList()
},
// 切换订单状态标签
async changeCoinTag(key) {
if (this.curCoinTag === key) return
this.curCoinTag = key
this.orderQuery.pageNum = 1
this.myExchangeOrder = []
// 设置查询状态
switch(key) {
case 0:
delete this.orderQuery.status // 全部状态
break
case 1:
this.orderQuery.status = 1 // 待发货
break
case 2:
this.orderQuery.status = 2 // 已收货
break
case 3:
this.orderQuery.status = 3 // 已完成
break
}
await this.getMyExchangeOrderFun()
},
// 加载更多订单
async changePageCoin() {
if (this.myExchangeOrder.length < this.orderTotal && !this.isLoading) {
this.orderQuery.pageNum++
await this.getMyExchangeOrderFun()
}
},
// 跳转登录
toLogin() {
this.$refs.loginRef.open()
}
}
}
</script>
<style lang="scss" scoped>
.activitypage {
height: 100vh;
background: #FFFFFF;
display: flex;
flex-direction: column;
.main-nav {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 100;
display: flex;
padding: 0 32rpx;
background: #FFFFFF;
border-bottom: 1rpx solid #F5F5F5;
height: 88rpx;
align-items: center;
.nav-item {
position: relative;
padding: 28rpx 0;
margin-right: 48rpx;
color: #606060;
font-size: 32rpx;
font-weight: 400;
&.nav-active {
color: #19367A;
font-weight: 600;
.nav-line {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 48rpx;
height: 4rpx;
background: #19367A;
border-radius: 2rpx;
}
}
}
}
.status-nav {
position: fixed;
top: 88rpx;
left: 0;
right: 0;
z-index: 99;
background: #FFFFFF;
white-space: nowrap;
padding: 20rpx 32rpx;
border-bottom: 1rpx solid #F5F5F5;
.status-nav-content {
display: inline-flex;
.status-item {
display: flex;
align-items: center;
justify-content: center;
width: 147rpx;
height: 64rpx;
margin-right: 16rpx;
font-size: 28rpx;
color: #606060;
background: #f9f9f9;
border-radius: 20rpx;
&.status-active {
color: #FFFFFF;
background: #19367A;
font-weight: 600;
}
}
}
}
.bg-white {
flex: 1;
margin-top: 172rpx; // 88rpx(导航栏) + 84rpx(标签栏)
overflow: hidden;
scroll-view {
height: 100%;
}
}
.activity-item {
border-radius: 12rpx;
background: #FFFFFF;
box-sizing: border-box;
border: 1px solid #E0E0E0;
width: 694rpx;
margin-top: 12rpx;
margin-bottom: 42rpx;
box-shadow: 0rpx 1rpx 3rpx 0rpx rgba(0, 0, 0, 0.1);
.left {
padding: 24rpx 20rpx;
border-radius: 20rpx;
background: #FFFFFF;
box-sizing: border-box;
border: 1px solid #E0E0E0;
width: 180rpx;
margin-top: -10rpx;
margin-bottom: -10rpx;
margin-left: -1rpx;
box-shadow: 0rpx 1rpx 3rpx 0rpx rgba(0, 0, 0, 0.1);
}
.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: 470rpx;
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;
.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;
}
}
}
.coin-item {
border-radius: 12rpx;
background: #FDFDFD;
padding: 24rpx;
box-sizing: border-box;
margin-bottom: 32rpx;
.coverImg {
border-radius: 12rpx;
background: #E9E9E9;
width: 132rpx;
height: 176rpx;
margin-right: 24rpx;
}
.title {
font-size: 24rpx;
font-weight: 500;
color: #0B0E26;
}
.subTitle {
font-size: 20rpx;
font-weight: 500;
color: #979797;
}
.num {
font-size: 48rpx;
font-weight: 500;
color: #2B2D33;
}
}
}
.word-all {
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
</style>