Compare commits
No commits in common. "b0a688df3658a4eb29b15d3848bdbde5b72bb753" and "740eea26839095b3e017b95533e2b7da77015c6c" have entirely different histories.
b0a688df36
...
740eea2683
@ -1,12 +1,11 @@
|
||||
<template>
|
||||
<view class="activity-item flex" v-if="isActivityVisible" @click="handleClick">
|
||||
<view class="store-tag" v-if="item.activityType === 1">指定门店</view>
|
||||
<view class="left">
|
||||
<image :src="item.brandLogo" class="brand-logo"></image>
|
||||
<image :src="item.brandLogo"></image>
|
||||
<view class="status-content">
|
||||
<text v-if="activityState === 'recruiting' && item.remainingDays > 0" class="status-label">招募剩余天数</text>
|
||||
<text v-else-if="activityState === 'recruiting' && item.remainingDays <= 0" class="status-label">活动招募已结束</text>
|
||||
<text v-else-if="activityState === 'inProgress'" class="status-label">距离达成还剩</text>
|
||||
<text v-if="activityState === 'recruiting' && item.remainingDays > 0">招募剩余天数</text>
|
||||
<text v-else-if="activityState === 'recruiting' && item.remainingDays <= 0">活动招募已结束</text>
|
||||
<text v-else-if="activityState === 'inProgress'">距离达成还剩</text>
|
||||
<view class="status-box">
|
||||
<template v-if="activityState === 'recruiting' && item.remainingDays > 0">
|
||||
<view class="days-left">
|
||||
@ -22,8 +21,8 @@
|
||||
</template>
|
||||
<template v-else-if="activityState === 'inProgress'">
|
||||
<view v-if="item.remainingBeerCount > 0" class="beer-count">
|
||||
<text class="count-num">{{item.remainingBeerCount}}</text>
|
||||
<text class="count-unit">桶</text>
|
||||
<text>{{item.remainingBeerCount}}</text>
|
||||
<text>桶</text>
|
||||
</view>
|
||||
</template>
|
||||
<template v-else-if="activityState === 'completed'">
|
||||
@ -36,17 +35,18 @@
|
||||
</view>
|
||||
<view class="right">
|
||||
<view class="title">{{ item.breweryName }}</view>
|
||||
<view class="sub">时间:首次扫码开始累计 <text class="highlight">{{item.duration}}天内</text></view>
|
||||
<view class="sub">目标:{{item.beerScope === 0 ? '品牌全系' : '以下'}}酒款累积扫码 ≥ <text class="highlight">{{ item.activityTarget}}桶</text></view>
|
||||
<scroll-view v-if="item.beers" scroll-x="true" class="scroll-img" enhanced show-scrollbar="false">
|
||||
<view class="sub">时间:首次扫码开始累计 <text style="color:#DE3C4B">{{item.duration}}天内</text></view>
|
||||
<view class="sub">目标:全系列酒款累积扫码 ≥ {{ item.activityTarget}}桶</view>
|
||||
<scroll-view v-if="item.beers" scroll-x="true" class="scroll-img">
|
||||
<view class="beer-box" v-for="(beer, beerIndex) in item.beers" :key="beerIndex" @click.stop="handleReview(beer)">
|
||||
<image v-if="beer.cover" :src="beer.cover" class="cover" mode="aspectFit"></image>
|
||||
<image v-if="beer.cover" :src="beer.cover" class="cover"></image>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="reward-info">
|
||||
<view class="flex align-center">
|
||||
<text v-if="item.activityRewardType == 2 || (item.activityRewardType == 1 && item.activityRewardGoods)" class="zeng">赠</text>
|
||||
<text v-if="item.activityRewardType == 1 && item.activityRewardGoods" class="reward-text">{{item.activityRewardGoods.goodsName}} {{item.activityRewardGoods.specs}} 奖励数量:{{item.activityRewardCount}}份</text>
|
||||
<text v-if="item.activityRewardType == 2" class="reward-text">品牌啤酒币 奖励数量 {{item.activityRewardCount}}枚</text>
|
||||
<text v-if="item.activityRewardType == 1 && item.activityRewardGoods" style="color: #0B0E26;font-size: 24rpx;">{{item.activityRewardGoods.goodsName}} * {{item.activityRewardCount}}</text>
|
||||
<text v-if="item.activityRewardType == 2" style="color: #0B0E26;font-size: 24rpx;">啤酒币 * {{item.activityRewardCount}}个</text>
|
||||
<text v-if="item.barAwardStatus" style="color: #0B0E26;font-size: 24rpx;">(已发放)</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@ -117,56 +117,34 @@ export default {
|
||||
position: relative;
|
||||
width: 702rpx;
|
||||
margin-bottom: 48rpx;
|
||||
transition: transform 0.2s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.98);
|
||||
}
|
||||
|
||||
.store-tag {
|
||||
position: absolute;
|
||||
top: 24rpx;
|
||||
right: 24rpx;
|
||||
font-size: 20rpx;
|
||||
color: #FFFFFF;
|
||||
background-color: #D42E78;
|
||||
padding: 6rpx 16rpx;
|
||||
border-radius: 8rpx;
|
||||
z-index: 2;
|
||||
box-shadow: 0 2rpx 6rpx rgba(212, 46, 120, 0.3);
|
||||
}
|
||||
// &:last-child {
|
||||
// margin-bottom: 0;
|
||||
// }
|
||||
|
||||
.right {
|
||||
width: 702rpx;
|
||||
min-height: 428rpx;
|
||||
background: #FFFFFF;
|
||||
border-radius: 20rpx;
|
||||
padding: 32rpx 32rpx 32rpx 200rpx;
|
||||
padding: 24rpx 24rpx 24rpx 200rpx;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 8rpx 16rpx rgba(0, 0, 0, 0.08);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
border: 1px solid #EFEDE9;
|
||||
box-shadow: 0rpx 1rpx 3rpx 0rpx rgba(0, 0, 0, 0.1);
|
||||
|
||||
.title {
|
||||
font-size: 36rpx;
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
line-height: 48rpx;
|
||||
color: #0B0E26;
|
||||
margin-bottom: 20rpx;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.sub {
|
||||
font-size: 28rpx;
|
||||
font-weight: 500;
|
||||
line-height: 44rpx;
|
||||
line-height: 40rpx;
|
||||
color: #0B0E26;
|
||||
margin-bottom: 20rpx;
|
||||
|
||||
.highlight {
|
||||
color: #D42E78;
|
||||
font-weight: bold;
|
||||
}
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
|
||||
.scroll-img {
|
||||
@ -174,62 +152,35 @@ export default {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
white-space: nowrap;
|
||||
height: 200rpx;
|
||||
margin-bottom: 24rpx;
|
||||
height: 144rpx;
|
||||
margin-bottom: 18rpx;
|
||||
overflow-x: auto;
|
||||
padding: 4rpx 0;
|
||||
|
||||
.beer-box {
|
||||
width: 120rpx;
|
||||
height: 170rpx;
|
||||
width: 100rpx;
|
||||
background: #FFFFFF;
|
||||
margin-right: 8rpx;
|
||||
margin-right: 20rpx;
|
||||
box-sizing: border-box;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: transform 0.2s;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
}
|
||||
display: inline-block;
|
||||
|
||||
.cover {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 12rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
object-fit: contain;
|
||||
width: 100rpx;
|
||||
height: 144rpx;
|
||||
border-radius: 10rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reward-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-top: 8rpx;
|
||||
}
|
||||
|
||||
.zeng {
|
||||
font-size: 22rpx;
|
||||
font-size: 20rpx;
|
||||
font-weight: bold;
|
||||
line-height: normal;
|
||||
text-align: center;
|
||||
color: #0B0E26;
|
||||
padding: 8rpx 16rpx;
|
||||
padding: 8rpx 12rpx;
|
||||
border-radius: 10rpx;
|
||||
background: #FEE034;
|
||||
margin-right: 20rpx;
|
||||
box-shadow: 0 2rpx 4rpx rgba(254, 224, 52, 0.3);
|
||||
}
|
||||
|
||||
.reward-text {
|
||||
color: #0B0E26;
|
||||
font-size: 26rpx;
|
||||
line-height: 36rpx;
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,18 +195,17 @@ export default {
|
||||
border-radius: 20rpx;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid #EFEDE9;
|
||||
z-index: 3;
|
||||
z-index: 1;
|
||||
box-shadow: 0rpx 1rpx 3rpx 0rpx rgba(0, 0, 0, 0.1);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.brand-logo {
|
||||
image {
|
||||
width: 132rpx;
|
||||
height: 132rpx;
|
||||
border-radius: 6rpx;
|
||||
margin-bottom: 40rpx;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.status-content {
|
||||
@ -263,7 +213,7 @@ export default {
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
|
||||
.status-label {
|
||||
text {
|
||||
color: #606060;
|
||||
font-size: 24rpx;
|
||||
font-weight: bold;
|
||||
@ -294,26 +244,18 @@ export default {
|
||||
}
|
||||
|
||||
.beer-count {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
justify-content: center;
|
||||
|
||||
.count-num {
|
||||
font-size: 48rpx;
|
||||
color: #19367A;
|
||||
font-weight: bold;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.count-unit {
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
color: #606060;
|
||||
margin-left: 4rpx;
|
||||
color: #0B0E26;
|
||||
|
||||
&:last-child {
|
||||
margin-left: 4rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.status-text {
|
||||
font-size: 28rpx;
|
||||
font-size: 24rpx;
|
||||
color: #19367A;
|
||||
font-weight: bold;
|
||||
|
||||
|
@ -198,17 +198,15 @@
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "活动详情",
|
||||
"navigationBarBackgroundColor": "#19367A",
|
||||
"navigationBarTextStyle": "white"
|
||||
"navigationBarBackgroundColor": "#FFFFFF",
|
||||
"navigationBarTextStyle": "black"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path" : "myActivityDetail",
|
||||
"style" :
|
||||
{
|
||||
"navigationBarTitleText" : "我的活动",
|
||||
"navigationBarBackgroundColor": "#19367A",
|
||||
"navigationBarTextStyle": "white"
|
||||
"navigationBarTitleText" : "我的活动"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -69,13 +69,67 @@
|
||||
style="padding: 16rpx 28rpx 0;background-color: #F2F2F2;overflow-y: auto;flex:1"
|
||||
@scrolltolower="changePage">
|
||||
<!-- 活动列表项 -->
|
||||
<activity-item
|
||||
v-for="(it, index) in myJoinList"
|
||||
:key="index"
|
||||
:item="it"
|
||||
@click="toInfo(it)"
|
||||
@review="toReview"
|
||||
></activity-item>
|
||||
<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>
|
||||
@ -118,42 +172,38 @@
|
||||
|
||||
<script>
|
||||
import loginPopup from '@/components/loginPopup.vue';
|
||||
import ActivityItem from '@/components/ActivityItem.vue'
|
||||
import { myJoinListApi, getMyExchangeOrder } from "@/api/user.js"
|
||||
import { getBarInfo } from "@/api/bar.js"
|
||||
export default {
|
||||
components: {
|
||||
loginPopup,
|
||||
ActivityItem
|
||||
loginPopup
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
loading: true,
|
||||
userInfo: null,
|
||||
barInfo: null,
|
||||
isLoggedIn: false,
|
||||
isVerified: false,
|
||||
tabCur: 0,
|
||||
curTag: 0,
|
||||
curCoinTag: 0,
|
||||
myJoinList: [],
|
||||
userInfo: null, // 用户信息
|
||||
barInfo: null, // 门店信息
|
||||
isLoggedIn: false, // 登录状态
|
||||
isVerified: false, // 认证状态
|
||||
tabCur: 0, // 当前选中的标签页
|
||||
curTag: 0, // 累积活动当前选中的标签
|
||||
curCoinTag: 0, // 啤酒币换购当前选中的标签
|
||||
myJoinList: [], // 我参与的活动列表
|
||||
queryForm: {
|
||||
status: 1,
|
||||
status: 1, // 活动状态
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
total: 0,
|
||||
myExchangeOrder:[],
|
||||
total: 0, // 活动总数
|
||||
myExchangeOrder:[], // 兑换订单列表
|
||||
orderQuery: {
|
||||
pageNum: 1,
|
||||
pageSize: 10
|
||||
},
|
||||
orderTotal: 0,
|
||||
isLoading: false,
|
||||
isRefreshing: false,
|
||||
hasNetwork: true,
|
||||
lastRefreshTime: 0,
|
||||
refreshDebounceTime: 1000,
|
||||
orderTotal: 0, // 订单总数
|
||||
isLoading: false, // 是否正在加载数据
|
||||
isRefreshing: false, // 是否正在刷新
|
||||
hasNetwork: true, // 网络状态
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
@ -251,6 +301,29 @@
|
||||
console.log('【getBarInfoFun】当前userStatus:', this.userStatus)
|
||||
},
|
||||
|
||||
// 初始化数据
|
||||
async initData() {
|
||||
try {
|
||||
this.loading = true
|
||||
const isLoggedIn = await this.checkLoginStatus()
|
||||
|
||||
if (isLoggedIn) {
|
||||
await this.getMyJoinList()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('初始化数据失败:', error)
|
||||
// 只在已认证状态下显示错误提示
|
||||
if (this.userStatus === 'verified') {
|
||||
uni.showToast({
|
||||
title: '加载失败',
|
||||
icon: 'none'
|
||||
})
|
||||
}
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
|
||||
// 检查用户信息变化
|
||||
async checkUserInfo() {
|
||||
try {
|
||||
@ -265,10 +338,7 @@
|
||||
const isLoggedIn = await this.checkLoginStatus()
|
||||
|
||||
if (isLoggedIn) {
|
||||
// 只在需要时刷新数据
|
||||
if (this.shouldRefreshData()) {
|
||||
await this.getMyJoinList()
|
||||
}
|
||||
await this.getMyJoinList()
|
||||
} else {
|
||||
this.myJoinList = []
|
||||
this.myExchangeOrder = []
|
||||
@ -287,16 +357,22 @@
|
||||
console.log('【loginSuccess】开始处理登录成功')
|
||||
this.loading = true
|
||||
|
||||
// 获取token和openId
|
||||
const token = uni.getStorageSync('token')
|
||||
const openId = uni.getStorageSync('openId')
|
||||
console.log('【loginSuccess】获取到的token:', token)
|
||||
console.log('【loginSuccess】获取到的openId:', openId)
|
||||
|
||||
if (token && openId) {
|
||||
// 更新登录状态
|
||||
this.isLoggedIn = true
|
||||
this.userInfo = {
|
||||
token,
|
||||
openId
|
||||
}
|
||||
console.log('【loginSuccess】更新登录状态:', this.isLoggedIn)
|
||||
|
||||
// 获取门店信息
|
||||
await this.getBarInfoFun()
|
||||
|
||||
// 重置页面状态
|
||||
@ -305,11 +381,12 @@
|
||||
this.myJoinList = []
|
||||
this.myExchangeOrder = []
|
||||
|
||||
// 只在需要时刷新数据
|
||||
if (this.userStatus === 'verified' && this.shouldRefreshData()) {
|
||||
// 重新加载数据
|
||||
if (this.userStatus === 'verified') {
|
||||
await this.getMyJoinList()
|
||||
}
|
||||
} else {
|
||||
console.log('【loginSuccess】token或openId不存在')
|
||||
this.isLoggedIn = false
|
||||
this.userInfo = null
|
||||
this.barInfo = null
|
||||
@ -317,6 +394,7 @@
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('【loginSuccess】登录成功处理失败:', error)
|
||||
// 只在已认证状态下显示错误提示
|
||||
if (this.userStatus === 'verified') {
|
||||
uni.showToast({
|
||||
title: '登录失败',
|
||||
@ -328,16 +406,6 @@
|
||||
}
|
||||
},
|
||||
|
||||
// 判断是否需要刷新数据
|
||||
shouldRefreshData() {
|
||||
const now = Date.now()
|
||||
if (now - this.lastRefreshTime < this.refreshDebounceTime) {
|
||||
return false
|
||||
}
|
||||
this.lastRefreshTime = now
|
||||
return true
|
||||
},
|
||||
|
||||
// 获取我的兑换订单
|
||||
async getMyExchangeOrderFun() {
|
||||
// 如果用户未认证,直接返回
|
||||
@ -382,17 +450,11 @@
|
||||
if (this.tabCur == 0) {
|
||||
this.myJoinList = []
|
||||
this.queryForm.pageNum = 1
|
||||
// 只在需要时刷新数据
|
||||
if (this.shouldRefreshData()) {
|
||||
await this.getMyJoinList()
|
||||
}
|
||||
await this.getMyJoinList()
|
||||
} else {
|
||||
this.myExchangeOrder = []
|
||||
this.orderQuery.pageNum = 1
|
||||
// 只在需要时刷新数据
|
||||
if (this.shouldRefreshData()) {
|
||||
await this.getMyExchangeOrderFun()
|
||||
}
|
||||
await this.getMyExchangeOrderFun()
|
||||
}
|
||||
},
|
||||
|
||||
@ -493,26 +555,23 @@
|
||||
|
||||
// 设置查询状态
|
||||
switch(key) {
|
||||
case 0:
|
||||
this.queryForm.status = 1
|
||||
case 0: // 累计中
|
||||
this.queryForm.status = 1 // 使用整数类型
|
||||
break
|
||||
case 1:
|
||||
this.queryForm.status = 2
|
||||
case 1: // 待兑付
|
||||
this.queryForm.status = 2 // 使用整数类型
|
||||
break
|
||||
case 2:
|
||||
this.queryForm.status = 3
|
||||
case 2: // 已兑付
|
||||
this.queryForm.status = 3 // 使用整数类型
|
||||
break
|
||||
case 3:
|
||||
this.queryForm.status = 4
|
||||
case 3: // 已完成
|
||||
this.queryForm.status = 4 // 使用整数类型
|
||||
break
|
||||
default:
|
||||
delete this.queryForm.status
|
||||
}
|
||||
|
||||
// 只在需要时刷新数据
|
||||
if (this.shouldRefreshData()) {
|
||||
await this.getMyJoinList()
|
||||
}
|
||||
await this.getMyJoinList()
|
||||
},
|
||||
|
||||
// 切换订单状态标签
|
||||
@ -526,23 +585,20 @@
|
||||
// 设置查询状态
|
||||
switch(key) {
|
||||
case 0:
|
||||
delete this.orderQuery.status
|
||||
delete this.orderQuery.status // 全部状态
|
||||
break
|
||||
case 1:
|
||||
this.orderQuery.status = 1
|
||||
this.orderQuery.status = 1 // 待发货
|
||||
break
|
||||
case 2:
|
||||
this.orderQuery.status = 2
|
||||
this.orderQuery.status = 2 // 已收货
|
||||
break
|
||||
case 3:
|
||||
this.orderQuery.status = 3
|
||||
this.orderQuery.status = 3 // 已完成
|
||||
break
|
||||
}
|
||||
|
||||
// 只在需要时刷新数据
|
||||
if (this.shouldRefreshData()) {
|
||||
await this.getMyExchangeOrderFun()
|
||||
}
|
||||
await this.getMyExchangeOrderFun()
|
||||
},
|
||||
|
||||
// 加载更多订单
|
||||
@ -863,5 +919,3 @@
|
||||
-webkit-box-orient: vertical;
|
||||
}
|
||||
</style>
|
||||
}
|
||||
</style>
|
@ -200,7 +200,7 @@
|
||||
</view>
|
||||
|
||||
<!-- 组件 -->
|
||||
<loginPopup ref="loginRef" @loginSuccess="loginSuccess"></loginPopup>
|
||||
<loginPopup ref="loginRef"></loginPopup>
|
||||
<createPoster v-if="showShare" ref="createPosterRef" :url="tempUrl" @close="showShare=false"></createPoster>
|
||||
<canvas type="2d" id="myCanvas" style="width: 360px;height: 570px;position: fixed;left:8888px"></canvas>
|
||||
</view>
|
||||
@ -249,8 +249,7 @@
|
||||
isAnimating: false,
|
||||
lastRefreshTime: 0,
|
||||
refreshDebounceTime: 1000,
|
||||
loading: false,
|
||||
needRefresh: false // 添加标记,用于标识是否需要刷新
|
||||
loading: false
|
||||
};
|
||||
},
|
||||
onLoad({beerId}) {
|
||||
@ -266,32 +265,23 @@
|
||||
// 检查登录状态
|
||||
checkLoginStatus() {
|
||||
const token = uni.getStorageSync('token')
|
||||
const wasLoggedIn = this.isLoggedIn
|
||||
this.isLoggedIn = !!token
|
||||
|
||||
if (this.isLoggedIn) {
|
||||
const barInfo = uni.getStorageSync('barInfo')
|
||||
this.isBarAuthenticated = barInfo && barInfo.authState === 1 // 1表示认证通过
|
||||
|
||||
// 如果之前未登录,现在登录了,标记需要刷新
|
||||
if (!wasLoggedIn) {
|
||||
this.needRefresh = true
|
||||
}
|
||||
} else {
|
||||
this.isBarAuthenticated = false
|
||||
}
|
||||
},
|
||||
|
||||
// 初始化页面数据
|
||||
async initPageData() {
|
||||
const now = Date.now()
|
||||
if (now - this.lastRefreshTime < this.refreshDebounceTime && !this.needRefresh) {
|
||||
if (now - this.lastRefreshTime < this.refreshDebounceTime) {
|
||||
return
|
||||
}
|
||||
|
||||
this.lastRefreshTime = now
|
||||
this.loading = true
|
||||
this.needRefresh = false // 重置刷新标记
|
||||
|
||||
try {
|
||||
// 重置数据
|
||||
@ -770,42 +760,6 @@
|
||||
}
|
||||
|
||||
this.currentTab = tab;
|
||||
},
|
||||
// 登录成功回调
|
||||
async loginSuccess() {
|
||||
console.log('登录成功,开始刷新页面数据')
|
||||
// 重置状态
|
||||
this.needRefresh = true
|
||||
this.loading = true
|
||||
|
||||
try {
|
||||
// 检查登录状态
|
||||
await this.checkLoginStatus()
|
||||
|
||||
// 如果已登录,刷新页面数据
|
||||
if (this.isLoggedIn) {
|
||||
// 重置数据
|
||||
this.reviewList = []
|
||||
this.queryForm.pageNum = 1
|
||||
|
||||
// 获取新数据
|
||||
await this.initPageData()
|
||||
|
||||
// 显示成功提示
|
||||
uni.showToast({
|
||||
title: '登录成功',
|
||||
icon: 'success'
|
||||
})
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('登录后刷新数据失败:', error)
|
||||
uni.showToast({
|
||||
title: '刷新数据失败',
|
||||
icon: 'none'
|
||||
})
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,137 +1,132 @@
|
||||
<template>
|
||||
<view class="page">
|
||||
<!-- 页面内容 -->
|
||||
<view class="page-content">
|
||||
<!-- 登录组件 -->
|
||||
<login-popup ref="loginPopup" @success="onLoginSuccess"></login-popup>
|
||||
|
||||
<!-- 进度展示区域 -->
|
||||
<view class="section">
|
||||
<view class="section-title">
|
||||
<template v-if="activityInfo.hasJoined">
|
||||
累计天数还剩
|
||||
<view class="page-content">
|
||||
<!-- 登录组件 -->
|
||||
<login-popup ref="loginPopup" @success="onLoginSuccess"></login-popup>
|
||||
<!-- 2. 进度展示区域 -->
|
||||
<view class="bg-white progress-box" style="border-radius: 0 0 12rpx 12rpx;">
|
||||
<!-- 标题文字 -->
|
||||
<view class="title-text section-title">
|
||||
<template v-if="activityInfo.hasJoined">
|
||||
累计天数还剩
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="activityInfo.remainingDays <= 0">
|
||||
活动招募已结束
|
||||
</template>
|
||||
<template v-else>
|
||||
<template v-if="activityInfo.remainingDays <= 0">
|
||||
活动招募已结束
|
||||
</template>
|
||||
<template v-else>
|
||||
活动招募即将结束
|
||||
</template>
|
||||
活动招募即将结束
|
||||
</template>
|
||||
</view>
|
||||
</template>
|
||||
</view>
|
||||
|
||||
<view class="info-list">
|
||||
<!-- 倒计时区域 -->
|
||||
<view class="info-item countdown-box">
|
||||
<view class="countdown-container">
|
||||
<view class="countdown-item">
|
||||
<text class="number">{{activityInfo.hasJoined ? activityInfo.remainingDuration : (activityInfo.remainingDays || '0')}}</text>
|
||||
<text class="unit">天</text>
|
||||
</view>
|
||||
<view class="countdown-item" v-if="!activityInfo.hasJoined">
|
||||
<text class="number">{{countdownTime.hours || '00'}}</text>
|
||||
<text class="unit">时</text>
|
||||
</view>
|
||||
<view class="countdown-item" v-if="!activityInfo.hasJoined">
|
||||
<text class="number">{{countdownTime.minutes || '00'}}</text>
|
||||
<text class="unit">分</text>
|
||||
</view>
|
||||
<view class="countdown-item" v-if="!activityInfo.hasJoined">
|
||||
<text class="number">{{countdownTime.seconds || '00'}}</text>
|
||||
<text class="unit">秒</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 倒计时区域 -->
|
||||
<view class="countdown-container">
|
||||
<view class="countdown-item">
|
||||
<text class="number">{{activityInfo.hasJoined ? activityInfo.remainingDuration : (activityInfo.remainingDays || '0')}}</text>
|
||||
<text class="unit">天</text>
|
||||
</view>
|
||||
<view class="countdown-item" v-if="!activityInfo.hasJoined">
|
||||
<text class="number">{{countdownTime.hours || '00'}}</text>
|
||||
<text class="unit">时</text>
|
||||
</view>
|
||||
<view class="countdown-item" v-if="!activityInfo.hasJoined">
|
||||
<text class="number">{{countdownTime.minutes || '00'}}</text>
|
||||
<text class="unit">分</text>
|
||||
</view>
|
||||
<view class="countdown-item" v-if="!activityInfo.hasJoined">
|
||||
<text class="number">{{countdownTime.seconds || '00'}}</text>
|
||||
<text class="unit">秒</text>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 活动信息区域 -->
|
||||
<view class="section">
|
||||
<view class="section-title">活动信息</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item" v-if="activityInfo.beers" @click="toBrand">
|
||||
<text>活动发起方</text>
|
||||
<view class="right-content">
|
||||
<image :src="activityInfo.beers[0].breweryLogo" class="brand-logo"></image>
|
||||
<text class="info-text">{{ activityInfo.beers[0].brandName}}</text>
|
||||
<text class="cuIcon-right"></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text>活动时间</text>
|
||||
<view class="right-content">
|
||||
<text class="info-text">首次扫码开始累计 <text class="highlight">{{activityInfo.duration || '-'}} 天内</text></text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-item">
|
||||
<text>活动目标</text>
|
||||
<view class="right-content">
|
||||
<text class="info-text">{{ activityInfo.beerScope === 0 ? '品牌全系列酒款' : '以下酒款' }}累计扫码 ≥ <text class="highlight">{{activityInfo.activityTarget || '-'}} 桶</text></text>
|
||||
<!-- 进度条区域 -->
|
||||
<view class="progress-bar">
|
||||
<view class="progress-track">
|
||||
<view class="progress-fill" :style="{ width: processNum + '%' }"></view>
|
||||
</view>
|
||||
<view class="progress-labels">
|
||||
<text class="start">0天</text>
|
||||
<text class="end">{{totalDays}}天</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- 3. 活动信息区域 -->
|
||||
<view class="bg-white padding margin-bottom-sm activity-info-box" style="border-radius:12rpx;margin-top: 24rpx;">
|
||||
<view v-if="activityInfo.beers" class="brand-info" @click="toBrand">
|
||||
<image :src="activityInfo.beers[0].breweryLogo" class="brand-logo"></image>
|
||||
<view class="brand-text">
|
||||
<view class="initiator">活动发起方</view>
|
||||
<view class="section-title">{{ activityInfo.beers[0].brandName}}</view>
|
||||
</view>
|
||||
<view class="cuIcon-right"></view>
|
||||
</view>
|
||||
<template v-if="currentTab == 1">
|
||||
<view class="activity-duration">首次扫码开始累计 <text class="duration-value">{{activityInfo.duration || '-'}} 天内</text></view>
|
||||
<view class="activity-target">
|
||||
{{ activityInfo.beer_scope === 0 ? '全系列酒款' : '以下酒款' }}累计扫码 ≥ {{activityInfo.activityTarget || '-'}} 桶
|
||||
</view>
|
||||
</template>
|
||||
<scroll-view v-if="currentTab == 1" scroll-x="true" class="scroll-container">
|
||||
<view v-for="(it, index) in activityInfo.beers" :key="index" style="display: inline-block;" class="row-box" @click="toReview(it)">
|
||||
<view class="beer-box">
|
||||
<image :src="it.cover" class="cover"></image>
|
||||
<view class="title word-all">{{ it.beerName || ''}}</view>
|
||||
<view class="desc word-all">{{ it.beerStyles || '' }}</view>
|
||||
<view class="desc word-all">{{ it.brandName ||'' }}</view>
|
||||
<view class="flex align-center num">
|
||||
<image src="@/static/vector.png" style="width: 20rpx;height: 20rpx;margin-right: 10rpx;">
|
||||
</image>
|
||||
{{ it.beerOverallRating || 0 }}({{ it.beerReviewsCount || 0}})
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 参与酒款区域 -->
|
||||
<view class="section">
|
||||
<view class="section-title">参与酒款</view>
|
||||
<scroll-view scroll-x="true" class="beer-scroll">
|
||||
<view class="beer-list">
|
||||
<view v-for="(it, index) in activityInfo.beers" :key="index" class="beer-card" @click="toBeerDetail(it)">
|
||||
<image :src="it.cover" class="beer-image"></image>
|
||||
<view class="beer-info">
|
||||
<text class="name">{{ it.beerName || ''}}</text>
|
||||
<text class="style">{{ it.beerStyles || '' }}</text>
|
||||
<view class="rating">
|
||||
<image src="@/static/vector.png" class="rating-icon"></image>
|
||||
<text>{{ it.beerOverallRating || 0 }}({{ it.beerReviewsCount || 0}})</text>
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
<!-- 1 商品 2 啤酒币 -->
|
||||
<view v-if="activityInfo.activityRewardType == 1 || currentTab == 1" class="bg-white padding margin-bottom-sm"
|
||||
style="border-radius:12rpx;">
|
||||
<view class="section-title margin-bottom-sm">挑战奖励</view>
|
||||
<view v-if="activityInfo.activityRewardGoods" class="flex align-center">
|
||||
<image :src="activityInfo.activityRewardGoods.goodsCover" style="width: 144rpx;height: 204rpx;margin-right:16rpx;border-radius: 12rpx;"></image>
|
||||
<view class="flex-1">
|
||||
<view class="flex flex-1 align-center">
|
||||
<view class="flex-1">
|
||||
<view class="word-all margin-bottom-sm" style="color:#1E2019">{{activityInfo.activityRewardGoods.goodsName}}</view>
|
||||
<!-- <view class="word-all margin-bottom-sm" style="color:rgba(30, 32, 25, 0.8)">风味西打酒</view>
|
||||
<view class="word-all margin-bottom-sm" style="color:#1E2019">TasteRoom 风味屋</view> -->
|
||||
</view>
|
||||
<view class="text-red text-right">x<text class="text-xxl text-bold">{{activityInfo.activityRewardCount}}</text></view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
</view>
|
||||
|
||||
<!-- 奖励区域 -->
|
||||
<view class="section" v-if="activityInfo.activityRewardType">
|
||||
<view class="section-title">挑战奖励</view>
|
||||
<view class="info-list">
|
||||
<view class="info-item reward-content" v-if="activityInfo.activityRewardType == 1">
|
||||
<image :src="activityInfo.activityRewardGoods.goodsCover" class="goods-image" mode="aspectFit"></image>
|
||||
<view class="goods-info">
|
||||
<text class="name">{{activityInfo.activityRewardGoods.goodsName}}</text>
|
||||
<view class="specs-info">
|
||||
<text class="specs-label">规格:</text>
|
||||
<text class="specs-value">{{activityInfo.activityRewardGoods.specs}}</text>
|
||||
</view>
|
||||
<text class="count">奖励数量:{{activityInfo.activityRewardCount}}份</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="info-item reward-content" v-if="activityInfo.activityRewardType == 2">
|
||||
<view class="coin-container">
|
||||
<image :src="activityInfo.brandLogo" class="coin-logo" mode="aspectFit"></image>
|
||||
</view>
|
||||
<view class="coin-info">
|
||||
<text class="name">{{activityInfo.breweryName}}品牌啤酒币</text>
|
||||
<text class="count">奖励数量: {{ activityInfo.activityRewardCount }}枚</text>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<!-- 底部操作栏 -->
|
||||
<view class="bottom-bar">
|
||||
<view class="action-button"
|
||||
:class="{
|
||||
'disabled': !isLoggedIn || !isVerified || (!activityInfo.hasJoined && activityInfo.remainingDays <= 0)
|
||||
}"
|
||||
@click="activityInfo.remainingDays <= 0 && !activityInfo.hasJoined ? null : handleButtonClick">
|
||||
<text class="cuIcon-qr_code"></text>
|
||||
<text>扫桶标自动开始累计</text>
|
||||
</view>
|
||||
<view v-if="activityInfo.activityRewardType == 2" class="bg-white padding margin-bottom-sm"
|
||||
style="border-radius:12rpx;">
|
||||
<view class="margin-bottom-sm">奖励</view>
|
||||
<view class="flex align-center">
|
||||
<!-- <image src="@/static/img/icon-logo.png" class="margin-right"
|
||||
style="width: 72rpx;height: 72rpx;border-radius: 30rpx;"></image> -->
|
||||
<view class="flex flex-1 align-center">
|
||||
<view class="flex-1 word-all" style="color:#1E2019">啤酒币</view>
|
||||
<view class="text-red text-right">x<text
|
||||
class="text-xxl text-bold">{{ activityInfo.activityRewardCount }}</text></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view style="height: 200rpx;background-color: transparent;"></view> -->
|
||||
<!-- 5. 底部操作栏 -->
|
||||
<view class="bg-white flex justify-center align-start padding-top bottom-bar">
|
||||
<view class="scan-btn"
|
||||
:class="{
|
||||
'btn-disabled': !isLoggedIn || !isVerified || (!activityInfo.hasJoined && activityInfo.remainingDays <= 0)
|
||||
}"
|
||||
@click="activityInfo.remainingDays <= 0 && !activityInfo.hasJoined ? null : handleButtonClick">
|
||||
<text class="cuIcon-qr_code margin-right-xs"></text>
|
||||
扫桶标自动开始累计
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
@ -365,8 +360,14 @@
|
||||
this.isLoggedIn = !!token;
|
||||
this.isVerified = barInfo && barInfo.authState === 1;
|
||||
},
|
||||
// 检查认证状态并处理
|
||||
checkAuthAndHandle() {
|
||||
handleButtonClick() {
|
||||
const token = uni.getStorageSync('token');
|
||||
if (!token) {
|
||||
this.$refs.loginPopup.open();
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查认证状态
|
||||
const barInfo = uni.getStorageSync('barInfo');
|
||||
if (!barInfo) {
|
||||
uni.showModal({
|
||||
@ -381,9 +382,10 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 处理不同的认证状态
|
||||
if (barInfo.authState === 2) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
@ -397,11 +399,14 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
return;
|
||||
} else if (barInfo.authState === 1) {
|
||||
return true;
|
||||
// 已认证,允许操作
|
||||
this.handleScan();
|
||||
return;
|
||||
}
|
||||
|
||||
// 未认证状态
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '请先认证门店',
|
||||
@ -414,18 +419,6 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
return false;
|
||||
},
|
||||
handleButtonClick() {
|
||||
const token = uni.getStorageSync('token');
|
||||
if (!token) {
|
||||
this.$refs.loginPopup.open();
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.checkAuthAndHandle()) {
|
||||
this.handleScan();
|
||||
}
|
||||
},
|
||||
onLoginSuccess(data) {
|
||||
// 登录成功后重新检查状态
|
||||
@ -437,32 +430,57 @@
|
||||
this.init();
|
||||
}
|
||||
|
||||
if (this.checkAuthAndHandle()) {
|
||||
// 检查认证状态
|
||||
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 === 2) {
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '您的门店正在认证中,请耐心等待',
|
||||
showCancel: true,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/index/registration'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
return;
|
||||
} else if (barInfo.authState === 1) {
|
||||
// 已认证,允许操作
|
||||
this.handleScan();
|
||||
}
|
||||
},
|
||||
// 跳转到酒款详情页
|
||||
toBeerDetail(beer) {
|
||||
if (!beer || !beer.id) {
|
||||
uni.showToast({
|
||||
title: '酒款信息不完整',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 确保id是数字类型
|
||||
const beerId = parseInt(beer.id);
|
||||
if (isNaN(beerId)) {
|
||||
uni.showToast({
|
||||
title: '酒款ID无效',
|
||||
icon: 'none'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
uni.navigateTo({
|
||||
url: '/pages/index/review?beerId=' + beerId
|
||||
// 未认证状态
|
||||
uni.showModal({
|
||||
title: '提示',
|
||||
content: '请先认证门店',
|
||||
showCancel: true,
|
||||
success: (res) => {
|
||||
if (res.confirm) {
|
||||
uni.navigateTo({
|
||||
url: '/pages/index/registration'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -481,323 +499,301 @@
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.page {
|
||||
min-height: 100vh;
|
||||
background: #F7F7F7;
|
||||
|
||||
.page-content {
|
||||
padding: 24rpx 32rpx;
|
||||
padding-bottom: calc(152rpx + env(safe-area-inset-bottom));
|
||||
}
|
||||
min-height: 100vh;
|
||||
color: #F9F9F9;
|
||||
padding-bottom: 200rpx;
|
||||
|
||||
.section {
|
||||
background: #FFFFFF;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 24rpx;
|
||||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.04);
|
||||
overflow: hidden;
|
||||
.progress-box {
|
||||
position: relative;
|
||||
background: #FFFFFF;
|
||||
padding: 32rpx;
|
||||
|
||||
.title-text {
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.countdown-container {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
margin-bottom: 32rpx;
|
||||
|
||||
.countdown-item {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
.number {
|
||||
font-size: 48rpx;
|
||||
color: #D42E78;
|
||||
font-weight: bold;
|
||||
font-family: 'DIN';
|
||||
background: #F5F5F5;
|
||||
padding: 8rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
}
|
||||
|
||||
.unit {
|
||||
font-size: 24rpx;
|
||||
color: #67677A;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
padding-left: 8rpx;
|
||||
|
||||
.progress-track {
|
||||
height: 16rpx;
|
||||
background: rgba(227, 227, 229, 0.6);
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
box-shadow: inset 0 2rpx 4rpx rgba(0, 0, 0, 0.05);
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #D42E78 0%, #19367A 100%);
|
||||
border-radius: 12rpx;
|
||||
transition: width 0.5s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
box-shadow: 0 2rpx 4rpx rgba(212, 46, 120, 0.2);
|
||||
}
|
||||
}
|
||||
|
||||
.progress-labels {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
font-family: Roboto;
|
||||
font-weight: 500;
|
||||
|
||||
&.start {
|
||||
color: #D42E78;
|
||||
}
|
||||
&.end {
|
||||
color: #19367A;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 横向滚动容器样式 */
|
||||
.scroll-container {
|
||||
display: flex; /* 使用弹性布局 */
|
||||
padding-top: 16rpx; /* 顶部内边距 */
|
||||
flex-direction: row; /* 水平方向排列 */
|
||||
white-space: nowrap; /* 防止内容换行 */
|
||||
min-height: 505rpx; /* 最小高度确保内容显示完整 */
|
||||
|
||||
/* 行容器样式 */
|
||||
.row-box {
|
||||
&:nth-child(1) { /* 第一个子元素特殊处理 */
|
||||
margin-left: 32rpx; /* 左侧外边距,与容器对齐 */
|
||||
}
|
||||
}
|
||||
|
||||
/* 啤酒卡片样式 */
|
||||
.beer-box {
|
||||
width: 208rpx; /* 卡片固定宽度 */
|
||||
background: #FFFFFF; /* 白色背景 */
|
||||
margin-right: 12rpx; /* 卡片间距 */
|
||||
margin-bottom: 36rpx; /* 底部外边距 */
|
||||
box-sizing: border-box; /* 盒模型计算方式 */
|
||||
display: flex; /* 弹性布局 */
|
||||
flex-direction: column; /* 垂直方向排列 */
|
||||
justify-content: flex-start; /* 内容从顶部开始排列 */
|
||||
|
||||
/* 啤酒图片封面样式 */
|
||||
.cover {
|
||||
width: 208rpx; /* 图片宽度 */
|
||||
height: 300rpx; /* 图片高度 */
|
||||
border-radius: 12rpx; /* 圆角效果 */
|
||||
margin-bottom: 16rpx; /* 与下方文字的间距 */
|
||||
}
|
||||
|
||||
/* 啤酒名称样式 */
|
||||
.title {
|
||||
font-size: 32rpx; /* 字体大小 */
|
||||
color: #030303; /* 文字颜色 */
|
||||
font-weight: 600; /* 字体粗细 */
|
||||
line-height: 48rpx; /* 行高 */
|
||||
margin-bottom: 8rpx; /* 底部间距 */
|
||||
white-space: nowrap; /* 不换行 */
|
||||
overflow: hidden; /* 溢出隐藏 */
|
||||
text-overflow: ellipsis; /* 文本溢出显示省略号 */
|
||||
}
|
||||
|
||||
/* 描述文本样式 */
|
||||
.desc {
|
||||
font-family: Roboto; /* 字体 */
|
||||
font-size: 24rpx; /* 字体大小 */
|
||||
font-weight: normal; /* 字体粗细 */
|
||||
line-height: 32rpx; /* 行高 */
|
||||
color: #606060; /* 文字颜色 */
|
||||
margin-bottom: 8rpx; /* 底部间距 */
|
||||
white-space: nowrap; /* 不换行 */
|
||||
overflow: hidden; /* 溢出隐藏 */
|
||||
text-overflow: ellipsis; /* 文本溢出显示省略号 */
|
||||
}
|
||||
|
||||
/* 数量/评分样式 */
|
||||
.num {
|
||||
display: flex; /* 弹性布局 */
|
||||
align-items: center; /* 垂直居中 */
|
||||
font-size: 20rpx; /* 字体大小 */
|
||||
color: #606060; /* 文字颜色 */
|
||||
line-height: 32rpx; /* 行高 */
|
||||
|
||||
image {
|
||||
margin-right: 10rpx; /* 图标右侧间距 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 奖励盒子
|
||||
.reward-box {
|
||||
background: #FFFFFF;
|
||||
border-radius: 30rpx;
|
||||
padding: 30rpx;
|
||||
margin-bottom: 36rpx;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
padding: 0 32rpx;
|
||||
|
||||
.progress-track {
|
||||
height: 12rpx;
|
||||
background: #E3E3E5;
|
||||
border-radius: 12rpx;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, #D42E78 0%, #19367A 100%);
|
||||
border-radius: 6rpx;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
}
|
||||
|
||||
.progress-labels {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: 12rpx;
|
||||
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
color: #67677A;
|
||||
|
||||
&.start {
|
||||
color: #D42E78;
|
||||
}
|
||||
&.end {
|
||||
color: #19367A;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.activity-info-box {
|
||||
padding: 32rpx;
|
||||
min-height: 360rpx; /* 设置最小高度 */
|
||||
|
||||
.brand-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 24rpx;
|
||||
// padding-bottom: 24rpx;
|
||||
// border-bottom: 1rpx solid #F5F5F5;
|
||||
border-radius: 12rpx;
|
||||
|
||||
.brand-logo {
|
||||
width: 88rpx;
|
||||
height: 88rpx;
|
||||
border-radius: 12rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
|
||||
.brand-text {
|
||||
flex: 1;
|
||||
|
||||
.initiator {
|
||||
color: #979797;
|
||||
font-size: 24rpx;
|
||||
font-weight: normal;
|
||||
margin-bottom: 16rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.activity-duration {
|
||||
color: #0B0E26;
|
||||
font-size: 28rpx;
|
||||
font-weight: normal;
|
||||
line-height: 40rpx;
|
||||
margin-bottom: 16rpx;
|
||||
|
||||
.duration-value {
|
||||
color: #D42E78;
|
||||
font-size: 32rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.activity-target {
|
||||
color: #0B0E26;
|
||||
font-size: 28rpx;
|
||||
margin-bottom: 24rpx;
|
||||
}
|
||||
|
||||
.scroll-container {
|
||||
margin-top: 16rpx;
|
||||
height: 505rpx; /* 固定高度确保滚动区域统一 */
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-bar {
|
||||
border-radius: 12rpx;
|
||||
height: 182rpx;
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
box-shadow: 0 -2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.scan-btn {
|
||||
width: 686rpx;
|
||||
height: 96rpx;
|
||||
background: #19367A;
|
||||
border-radius: 12rpx;
|
||||
color: #FFFFFF;
|
||||
font-size: 32rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&.btn-disabled {
|
||||
background: #E5E6EB;
|
||||
color: #86909C;
|
||||
}
|
||||
|
||||
.cuIcon-qr_code {
|
||||
font-size: 36rpx;
|
||||
margin-right: 16rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: 600;
|
||||
padding: 32rpx;
|
||||
color: #333333;
|
||||
position: relative;
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 32rpx;
|
||||
bottom: 0;
|
||||
width: 48rpx;
|
||||
height: 4rpx;
|
||||
background: #19367A;
|
||||
border-radius: 2rpx;
|
||||
}
|
||||
color: #0B0E26;
|
||||
line-height: 48rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.info-list {
|
||||
.info-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 32rpx;
|
||||
border-bottom: 1rpx solid rgba(0, 0, 0, 0.05);
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.right-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 16rpx;
|
||||
|
||||
.brand-logo {
|
||||
width: 48rpx;
|
||||
height: 48rpx;
|
||||
border-radius: 50%;
|
||||
border: 1rpx solid #19367A;
|
||||
}
|
||||
|
||||
.info-text {
|
||||
font-size: 28rpx;
|
||||
color: #666666;
|
||||
text-align: right;
|
||||
|
||||
.highlight {
|
||||
color: #19367A;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.cuIcon-right {
|
||||
color: #CCCCCC;
|
||||
font-size: 24rpx;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.countdown-box {
|
||||
padding: 24rpx 32rpx;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
.countdown-container {
|
||||
display: flex;
|
||||
gap: 24rpx;
|
||||
justify-content: center;
|
||||
|
||||
.countdown-item {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
||||
.number {
|
||||
font-size: 48rpx;
|
||||
color: #D42E78;
|
||||
font-weight: bold;
|
||||
font-family: 'DIN';
|
||||
background: #F5F5F5;
|
||||
padding: 8rpx 12rpx;
|
||||
border-radius: 12rpx;
|
||||
min-width: 80rpx;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.unit {
|
||||
font-size: 24rpx;
|
||||
color: #67677A;
|
||||
margin-left: 8rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.beer-scroll {
|
||||
padding: 24rpx 0;
|
||||
|
||||
.beer-list {
|
||||
display: flex;
|
||||
padding: 0 32rpx;
|
||||
gap: 24rpx;
|
||||
|
||||
.beer-card {
|
||||
width: 200rpx;
|
||||
flex-shrink: 0;
|
||||
background: #F9F9F9;
|
||||
border-radius: 12rpx;
|
||||
padding: 16rpx;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:active {
|
||||
transform: scale(0.95);
|
||||
background: #F0F0F0;
|
||||
}
|
||||
|
||||
.beer-image {
|
||||
width: 200rpx;
|
||||
height: 280rpx;
|
||||
border-radius: 8rpx;
|
||||
margin-bottom: 12rpx;
|
||||
}
|
||||
|
||||
.beer-info {
|
||||
.name {
|
||||
font-size: 28rpx;
|
||||
color: #333333;
|
||||
font-weight: bold;
|
||||
margin-bottom: 8rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.style {
|
||||
font-size: 24rpx;
|
||||
color: rgba(51, 51, 51, 0.8);
|
||||
margin-bottom: 8rpx;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.rating {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8rpx;
|
||||
|
||||
.rating-icon {
|
||||
width: 20rpx;
|
||||
height: 20rpx;
|
||||
}
|
||||
|
||||
text {
|
||||
font-size: 24rpx;
|
||||
color: #666666;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reward-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 24rpx;
|
||||
padding: 0 32rpx 32rpx;
|
||||
|
||||
.goods-image {
|
||||
width: 160rpx;
|
||||
height: 160rpx;
|
||||
border-radius: 12rpx;
|
||||
background: #FFFFFF;
|
||||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.goods-info {
|
||||
flex: 1;
|
||||
|
||||
.name {
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 12rpx;
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.specs-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 12rpx;
|
||||
|
||||
.specs-label {
|
||||
font-size: 32rpx;
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
.specs-value {
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.count {
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.coin-container {
|
||||
position: relative;
|
||||
width: 120rpx;
|
||||
height: 120rpx;
|
||||
flex-shrink: 0;
|
||||
|
||||
.coin-logo {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
background: #FFFFFF;
|
||||
padding: 16rpx;
|
||||
box-sizing: border-box;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
.coin-info {
|
||||
flex: 1;
|
||||
|
||||
.name {
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
margin-bottom: 12rpx;
|
||||
display: block;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.count {
|
||||
font-size: 32rpx;
|
||||
color: #333333;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.bottom-bar {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #FFFFFF;
|
||||
padding: 24rpx 32rpx;
|
||||
padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
box-shadow: 0 -4rpx 12rpx rgba(0, 0, 0, 0.05);
|
||||
|
||||
.action-button {
|
||||
width: 686rpx;
|
||||
height: 88rpx;
|
||||
background: linear-gradient(135deg, #19367A, #2C4C99);
|
||||
border-radius: 44rpx;
|
||||
color: #FFFFFF;
|
||||
font-size: 32rpx;
|
||||
font-weight: 500;
|
||||
letter-spacing: 2rpx;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8rpx;
|
||||
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);
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
background: #EFEFEF;
|
||||
color: #999999;
|
||||
box-shadow: none;
|
||||
|
||||
&:active {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cuIcon-qr_code {
|
||||
font-size: 36rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 15 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 14 KiB |
BIN
static/tick-circle@2x.png
Normal file
BIN
static/tick-circle@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
Loading…
x
Reference in New Issue
Block a user