962 lines
24 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">
<!-- 错误状态页面 -->
<template v-if="showError || info.qrcode.qrcodeStatus == 2">
<view class="error-page">
<!-- 位置错误 -->
<template v-if="errorType === 'location'">
<image src="/static/location.svg" class="status-icon"></image>
<view class="status-title">超出门店范围</view>
<view class="status-desc">您现在未在您门店定位的范围</view>
<view class="status-desc">请在门店范围100米内重新扫码</view>
</template>
<!-- 已失效 -->
<template v-if="errorType === 'expired' || info.qrcode.qrcodeStatus == 2">
<image src="/static/warning-2.png" class="status-icon"></image>
<view class="status-title">{{ info.qrcode.statusDesc || '二维码已失效' }}</view>
<view class="status-desc">{{ info.qrcode.statusMessage || '该二维码已超出可用范围' }}</view>
</template>
<!-- 商品信息卡片 -->
<view v-if="beer" class="product-card">
<view class="product-content">
<view class="product-image">
<image :src="beer.cover" class="cover"></image>
</view>
<view class="product-info">
<view class="product-name">{{ beer.beerName }}</view>
<view class="product-brand">{{ beer.brandName }}</view>
<view class="product-details">
<view class="detail-item">
<text class="detail-label">生产日期:</text>
<text class="detail-value">{{ beer.createTime ? beer.createTime.split(' ')[0] : '' }}</text>
</view>
<view class="detail-item">
<text class="detail-label">净含量:</text>
<text class="detail-value">{{ beer.netContent }}</text>
</view>
</view>
</view>
</view>
</view>
<!-- 返回按钮 -->
<view class="error-action">
<view class="action-btn" @click="back">
<image src="/static/undo.svg" class="btn-icon"></image>
<text>返回</text>
</view>
</view>
</view>
</template>
<!-- 正常状态页面 -->
<template v-else>
<view class="flex-1" style="overflow-y: auto;">
<!-- 已领取 -->
<view v-if="info.qrcode.qrcodeStatus == 1 && false" class="lq-state-box">
<image src="@/static/information.png" class="img"></image>
<text>该桶产品已于 {{ info.qrcode.verifyTime }} 扫码领取返利</text>
</view>
<!-- 转为赠品 -->
<view v-if="info.qrcode.qrcodeStatus == 3" class="lq-state-box gift-state">
<image src="@/static/gift.png" class="img"></image>
<text>该桶产品已转为赠品</text>
</view>
<!-- 领取成功 -->
<view v-if="info.qrcode.qrcodeStatus == 1" class="scs-state-box">
<image src="/static/tick-circle.svg" class="img"></image>
<text>领取成功!</text>
</view>
<!-- 产品信息卡片 -->
<view v-if="beer && info.qrcode.qrcodeStatus == 0" class="product-card">
<view class="section-title">
<text>商品详细</text>
</view>
<view class="product-content">
<view class="product-image">
<image :src="beer.cover" class="cover"></image>
</view>
<view class="product-info">
<view class="product-name">{{ beer.beerName }}</view>
<view class="product-brand">{{ beer.brandName }}</view>
<view class="product-details">
<view class="detail-item">
<text class="detail-label">生产日期:</text>
<text class="detail-value">{{ beer.launchDate }}</text>
</view>
<view class="detail-item">
<text class="detail-label">净含量:</text>
<text class="detail-value">{{ beer.netContent }}</text>
</view>
</view>
<view class="product-rating">
<view class="rating-stars">
<text class="cuIcon-favorfill" style="color: #FFBC11;"></text>
<text class="rating-value">{{ beer.beerOverallRating }}</text>
</view>
<text class="rating-count">{{beer.beerReviewsCount}} 条评论</text>
</view>
</view>
</view>
</view>
<!-- 品牌福利卡片(领取成功状态) -->
<view v-if="info.qrcode.qrcodeStatus == 1" class="benefit-card">
<view class="section-title">
<text>品牌福利已领取</text>
</view>
<view class="benefit-content">
<view class="benefit-title">{{ beer.scanCoinCount}}枚({{beer.brandName}})品牌啤酒币已到账</view>
<text class="benefit-subtitle">品牌啤酒币可用于兑换好礼</text>
</view>
</view>
<!-- 活动选择提示 -->
<view v-if="activitySum > 1 && info.qrcode.qrcodeStatus == 0" class="activity-tip">
<text class="tip-icon">!</text>
<text class="tip-text">该产品有多个进行中活动重叠,请<text class="highlight">选择要计入的活动</text></text>
</view>
<!-- 活动列表(领取成功状态) -->
<template v-if="info.qrcode.qrcodeStatus == 1">
<!-- 品牌活动 -->
<view v-for="(it, index) in activity.filter(item => item.id === activityId)" :key="index"
class="activity-card">
<view class="activity-content">
<view class="activity-left">
<image :src="it.brandLogo" class="brand-logo"></image>
<view class="progress-info">
<text class="progress-label">距离达成还剩</text>
<view class="progress-value">
<text v-if="it.remainingBeerCount <= 0" class="completed">已达标</text>
<text v-else class="remaining">{{ it.remainingBeerCount}}桶</text>
</view>
</view>
</view>
<view class="activity-right">
<view class="activity-name">{{ it.activityName }}</view>
<view class="activity-detail">时间:首次扫码开始计时 <text class="highlight">{{it.duration}}天内</text></view>
<view class="activity-detail">目标:{{ it.beer_scope === 0 ? '全系列酒款' : '以下酒款' }}累计扫码 ≥ {{ it.activityTarget}}桶</view>
<scroll-view v-if="it.beers" scroll-x="true" class="beer-scroll">
<view class="beer-item" v-for="(beer, index) in it.beers" :key="index">
<image v-if="beer.cover" :src="beer.cover" class="beer-cover"></image>
</view>
</scroll-view>
<view class="reward-info">
<text class="reward-label">赠</text>
<text v-if="it.activityRewardType == 1 && it.activityRewardGoods" class="reward-value">
{{it.activityRewardGoods.goodsName}} * {{it.activityRewardCount}}
</text>
<text v-if="it.activityRewardType == 2" class="reward-value">
啤酒币 * {{it.activityRewardCount}}个
</text>
</view>
</view>
</view>
</view>
<!-- 平台活动 -->
<view v-for="(it, index) in platformActivity.filter(item => item.id === platformActivityId)" :key="index"
class="activity-card">
<view class="activity-content">
<view class="activity-left">
<image :src="it.brandLogo" class="brand-logo"></image>
<view class="progress-info">
<text class="progress-label">距离达成还剩</text>
<view class="progress-value">
<text v-if="it.remainingBeerCount <= 0" class="completed">已达标</text>
<text v-else class="remaining">{{ it.remainingBeerCount}}桶</text>
</view>
</view>
</view>
<view class="activity-right">
<view class="activity-name">{{ it.activityName }}</view>
<view class="activity-detail">时间:首次扫码开始计时 <text class="highlight">{{it.duration}}天内</text></view>
<view class="activity-detail">目标:{{ it.beer_scope === 0 ? '全系列酒款' : '以下酒款' }}累计扫码 ≥ {{ it.activityTarget}}桶</view>
<scroll-view scroll-x="true" class="beer-scroll">
<view class="beer-item" v-for="(beer, index) in it.beers" :key="index">
<image v-if="beer.cover" :src="beer.cover" class="beer-cover"></image>
</view>
</scroll-view>
<view class="reward-info">
<text class="reward-label"></text>
<text v-if="it.activityRewardType == 1 && it.activityRewardGoods" class="reward-value">
{{it.activityRewardGoods.goodsName}} * {{it.activityRewardCount}}
</text>
<text v-if="it.activityRewardType == 2" class="reward-value">
啤酒币 * {{it.activityRewardCount}}
</text>
</view>
</view>
</view>
</view>
</template>
</view>
<!-- 底部操作区 -->
<view class="footer">
<view v-if="info.qrcode.qrcodeStatus == 2" class="warning-tip">
<image src="@/static/warning-2.png" class="warning-icon"></image>
<text>所有酒款只可领取一次请确认后操作</text>
</view>
<view class="action-buttons">
<view v-if="info.qrcode.qrcodeStatus != 1 && info.qrcode.qrcodeStatus != 3"
class="action-btn cancel-btn" @click="back">
<image src="/static/undo.svg" class="btn-icon"></image>
<text>回头再说</text>
</view>
<view v-else class="action-btn cancel-btn" @click="toWinelist">
<image src="@/static/document.png" class="btn-icon"></image>
<text>生成酒单</text>
</view>
<view v-if="info.qrcode.qrcodeStatus == 0" class="action-btn primary-btn" @click="handleReceive">
<image src="/static/send-2.svg" class="btn-icon"></image>
<text>立即领取</text>
</view>
<view v-else-if="info.qrcode.qrcodeStatus == 3" class="action-btn gift-btn" @click="share">
<image src="/static/send-2.svg" class="btn-icon"></image>
<text>分享赠品</text>
</view>
<view v-else class="action-btn primary-btn" @click="share">
<image src="/static/send-2.svg" class="btn-icon"></image>
<text>分享上新</text>
</view>
</view>
</view>
</template>
</view>
</template>
<script>
import {
consumeCode,
getQrcodeInfo
} from '@/api/bar.js'
import BeerCard from '@/components/BeerCard.vue'
export default {
components: {
BeerCard
},
data() {
return {
showError: false,
info: {
qrcode: {
qrcodeStatus: null, // 0: 待领取, 1: 领取成功, 2: 已失效, 3: 转为赠品
},
},
activity: [], // 活动列表
platformActivity: [], // 平台活动
activityList: [],
activitySum: 0, // 活动数量
beer: null,
result: null, // 扫码结果 code
activityId: null, // 活动id
platformActivityId: null, // 平台活动id
latitude: null,
longitude: null,
errorType: null, // 错误类型: location-位置错误, expired-已失效
};
},
onLoad({
result,
latitude,
longitude
}) {
this.result = result
this.latitude = latitude
this.longitude = longitude
// 查询二维码信息
this.getQrcodeInfoFun(result)
},
methods: {
// 查询二维码信息
getQrcodeInfoFun(code) {
getQrcodeInfo({
code,
latitude: this.latitude,
longitude: this.longitude
}).then(res => {
console.log(res.data)
this.info = res.data
this.beer = res.data.beer
this.activity = res.data.activity || []
this.platformActivity = res.data.platformActivity || []
if (this.activity && this.activity.length > 0) {
this.activitySum += this.activity.length
this.activityId = this.activity[0].id
}
if (this.platformActivity && this.platformActivity.length > 0) {
this.activitySum += this.platformActivity.length
this.platformActivityId = this.platformActivity[0].id
}
}).catch(err => {
console.error('获取二维码信息失败:', err)
if (err.code === 500 && err.msg === '请在酒吧附近100米范围内扫码') {
this.showError = true
this.errorType = 'location'
} else if (err.code === 500 && err.msg.includes('已失效')) {
this.errorType = 'expired'
} else {
uni.showToast({
title: err.msg || '获取信息失败',
icon: 'none'
})
}
})
},
// 立即领取
handleReceive() {
const data = {
code: this.result,
latitude: this.latitude,
longitude: this.longitude
}
if (this.activityId) {
data.activityId = this.activityId
}
if (this.platformActivityId) {
data.platformActivityId = this.platformActivityId
}
consumeCode(data).then(res => {
console.log(res)
uni.showToast({
title: '领取成功',
icon: 'success'
})
this.getQrcodeInfoFun(this.result)
}).catch(err => {
console.error('领取失败:', err)
if (err.code === 500 && err.msg === '请在酒吧附近100米范围内扫码') {
this.showError = true
} else {
uni.showToast({
title: err.msg || '领取失败',
icon: 'none'
})
}
})
},
back() {
if (this.info.qrcode.qrcodeStatus == 1) {
// 领取成功时返回首页
uni.switchTab({
url: '/pages/index/index'
})
} else {
// 其他情况正常返回上一页
uni.navigateBack()
}
},
// 选择品牌方活动
selectPPF(item) {
this.activityId = item.id
},
// 选择平台活动
selectPlatform(item) {
this.platformActivityId = item.id
},
// 生成酒单
toWinelist() {
uni.navigateTo({
url: '/pagesActivity/winelist?beerId=' + this.beer.id
})
},
share() {
uni.downloadFile({
url: this.beer.cover,
success: (res) => {
console.log(res)
// #ifdef MP-WEIXIN
uni.showShareImageMenu({
provider: 'weixin',
path: res.tempFilePath,
shareType: 0,
success: (res) => {
console.log(res)
},
fail: (err) => {
console.log(err)
}
})
// #endif
}
})
}
}
}
</script>
<style lang="scss" scoped>
.page {
height: 100vh;
background-color: #F5F7FA;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 0rpx 26rpx 60rpx;
.error-page {
display: flex;
flex-direction: column;
align-items: center;
padding-top: 120rpx;
.status-icon {
width: 160rpx;
height: 160rpx;
margin-bottom: 40rpx;
}
.status-title {
font-size: 36rpx;
color: #3D3D3D;
font-weight: 600;
margin-bottom: 16rpx;
}
.status-desc {
font-size: 28rpx;
color: #5F5F63;
font-weight: 400;
margin-bottom: 12rpx;
text-align: center;
&:last-of-type {
margin-bottom: 60rpx;
}
}
.product-card {
width: 100%;
background: #FFFFFF;
border-radius: 24rpx;
box-shadow: 0px 8rpx 24rpx rgba(0, 0, 0, 0.08);
padding: 36rpx;
margin-bottom: 40rpx;
.product-content {
display: flex;
.product-image {
margin-right: 28rpx;
.cover {
width: 200rpx;
height: 300rpx;
border-radius: 16rpx;
box-shadow: 0px 8rpx 16rpx rgba(0, 0, 0, 0.12);
}
}
.product-info {
flex: 1;
.product-name {
font-size: 40rpx;
color: #141415;
font-weight: 600;
margin-bottom: 16rpx;
}
.product-brand {
font-size: 30rpx;
color: #5F5F63;
font-weight: 500;
margin-bottom: 16rpx;
}
.product-details {
margin-bottom: 28rpx;
.detail-item {
display: flex;
margin-bottom: 12rpx;
font-size: 28rpx;
.detail-label {
color: #3D3D3D;
margin-right: 8rpx;
font-weight: 500;
}
.detail-value {
color: #5F5F63;
font-weight: 400;
}
}
}
}
}
}
.error-action {
width: 100%;
padding: 0 40rpx;
margin-top: 40rpx;
.action-btn {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 96rpx;
background: #D42E78;
border-radius: 12rpx;
font-size: 28rpx;
color: #FFFFFF;
font-weight: 500;
box-shadow: 0px 4rpx 12rpx rgba(0, 0, 0, 0.1);
.btn-icon {
width: 40rpx;
height: 40rpx;
margin-right: 12rpx;
filter: brightness(0) invert(1);
}
}
}
}
/* 状态提示样式 */
.lq-state-box {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 92rpx;
padding-top: 116rpx;
.img {
width: 160rpx;
height: 160rpx;
margin-bottom: 26rpx;
}
text {
font-size: 32rpx;
color: #5F5F63;
font-weight: 400;
}
}
.scs-state-box {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 40rpx;
padding-top: 40rpx;
font-size: 36rpx;
color: #1E2019;
font-weight: 600;
.img {
width: 160rpx;
height: 160rpx;
margin-right: 48rpx;
}
}
/* 卡片通用样式 */
.section-title {
margin-bottom: 28rpx;
text {
font-size: 36rpx;
color: #0B0E26;
font-weight: 600;
position: relative;
padding-left: 24rpx;
&::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 6rpx;
height: 32rpx;
background: linear-gradient(180deg, #D42E78 0%, #19367A 100%);
border-radius: 3rpx;
}
}
}
/* 产品卡片样式 */
.product-card {
background: #FFFFFF;
border-radius: 24rpx;
box-shadow: 0px 8rpx 24rpx rgba(0, 0, 0, 0.08);
padding: 36rpx;
margin-bottom: 40rpx;
.product-content {
display: flex;
.product-image {
margin-right: 28rpx;
.cover {
width: 200rpx;
height: 300rpx;
border-radius: 16rpx;
box-shadow: 0px 8rpx 16rpx rgba(0, 0, 0, 0.12);
}
}
.product-info {
flex: 1;
.product-name {
font-size: 40rpx;
color: #141415;
font-weight: 600;
margin-bottom: 16rpx;
}
.product-brand {
font-size: 30rpx;
color: #5F5F63;
font-weight: 600;
margin-bottom: 16rpx;
}
.product-details {
margin-bottom: 28rpx;
.detail-item {
display: flex;
margin-bottom: 12rpx;
font-size: 28rpx;
.detail-label {
color: #3D3D3D;
margin-right: 8rpx;
font-weight: 500;
}
.detail-value {
color: #5F5F63;
font-weight: 400;
}
}
}
.product-rating {
display: flex;
align-items: center;
.rating-stars {
display: flex;
align-items: center;
background: #F5F5F5;
padding: 8rpx 16rpx;
border-radius: 16rpx;
margin-right: 16rpx;
.rating-value {
font-size: 28rpx;
color: #5F5F63;
font-weight: 400;
margin-left: 8rpx;
}
}
.rating-count {
font-size: 28rpx;
color: #5F5F63;
font-weight: 400;
}
}
}
}
}
/* 福利卡片样式 */
.benefit-card {
background: #FFFFFF;
border-radius: 24rpx;
box-shadow: 0px 8rpx 24rpx rgba(0, 0, 0, 0.08);
padding: 36rpx;
margin-bottom: 40rpx;
.benefit-content {
.benefit-title {
font-size: 32rpx;
font-weight: 600;
color: #3D3D3D;
margin-bottom: 12rpx;
}
.benefit-subtitle {
font-size: 24rpx;
color: rgba(151, 151, 151, 0.75);
font-weight: 400;
}
}
}
/* 活动提示样式 */
.activity-tip {
display: flex;
align-items: center;
background: rgba(254, 224, 52, 0.2);
border-radius: 16rpx;
padding: 20rpx 28rpx;
margin-bottom: 32rpx;
box-shadow: 0px 4rpx 12rpx rgba(0, 0, 0, 0.05);
.tip-icon {
width: 40rpx;
height: 40rpx;
background: #FEE034;
color: #0B0E26;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 500;
margin-right: 16rpx;
}
.tip-text {
font-size: 24rpx;
color: #5E5F60;
font-weight: 400;
.highlight {
color: #DE3C4B;
font-weight: 500;
}
}
}
/* 活动卡片样式 */
.activity-card {
background: #FFFFFF;
border-radius: 24rpx;
box-shadow: 0px 8rpx 24rpx rgba(0, 0, 0, 0.08);
padding: 28rpx;
margin-bottom: 32rpx;
border: 2rpx solid transparent;
transition: all 0.3s;
&.activity-card-active {
border-color: #FEE034;
background: rgba(254, 224, 52, 0.05);
box-shadow: 0px 12rpx 32rpx rgba(0, 0, 0, 0.12);
}
.activity-content {
display: flex;
.activity-left {
width: 180rpx;
display: flex;
flex-direction: column;
align-items: center;
padding: 20rpx;
background: #F9F9F9;
border-radius: 16rpx;
margin-right: 28rpx;
box-shadow: 0px 4rpx 12rpx rgba(0, 0, 0, 0.05);
.brand-logo {
width: 140rpx;
height: 140rpx;
border-radius: 16rpx;
margin-bottom: 20rpx;
}
.progress-info {
text-align: center;
.progress-label {
font-size: 24rpx;
color: #9E9E9E;
font-weight: 400;
margin-bottom: 8rpx;
}
.progress-value {
.completed {
font-size: 32rpx;
color: #DE3C4B;
font-weight: 500;
}
.remaining {
font-size: 40rpx;
color: #DE3C4B;
font-weight: 500;
}
}
}
}
.activity-right {
flex: 1;
.activity-name {
font-size: 32rpx;
font-weight: 600;
color: #0B0E26;
margin-bottom: 20rpx;
}
.activity-detail {
font-size: 26rpx;
color: #0B0E26;
font-weight: 400;
margin-bottom: 16rpx;
.highlight {
color: #DE3C4B;
font-weight: 500;
}
}
.beer-scroll {
width: 100%;
white-space: nowrap;
margin-bottom: 20rpx;
.beer-item {
display: inline-block;
margin-right: 16rpx;
.beer-cover {
width: 100rpx;
height: 144rpx;
border-radius: 8rpx;
box-shadow: 0px 4rpx 8rpx rgba(0, 0, 0, 0.1);
}
}
}
.reward-info {
display: flex;
align-items: center;
.reward-label {
background: #FEE034;
color: #0B0E26;
font-size: 24rpx;
font-weight: 500;
padding: 6rpx 12rpx;
border-radius: 8rpx;
margin-right: 12rpx;
}
.reward-value {
font-size: 26rpx;
color: #0B0E26;
font-weight: 400;
}
}
}
}
}
/* 底部区域样式 */
.footer {
margin-top: 40rpx;
.warning-tip {
display: flex;
align-items: center;
background: rgba(233, 233, 233, 0.38);
border-radius: 16rpx;
padding: 20rpx 28rpx;
margin-bottom: 32rpx;
box-shadow: 0px 4rpx 12rpx rgba(0, 0, 0, 0.05);
.warning-icon {
width: 30rpx;
height: 30rpx;
margin-right: 12rpx;
}
text {
font-size: 24rpx;
color: #5E5F60;
font-weight: 400;
}
}
.action-buttons {
display: flex;
justify-content: space-between;
gap: 24rpx;
padding: 0 12rpx;
.action-btn {
display: flex;
align-items: center;
justify-content: center;
width: calc(50% - 12rpx);
height: 96rpx;
border-radius: 12rpx;
font-size: 28rpx;
font-weight: 500;
box-shadow: 0px 4rpx 12rpx rgba(0, 0, 0, 0.1);
.btn-icon {
width: 40rpx;
height: 40rpx;
margin-right: 12rpx;
}
&.cancel-btn {
background-color: #D42E78;
color: #FFFFFF;
font-weight: 500;
.btn-icon {
filter: brightness(0) invert(1);
}
}
&.primary-btn {
background-color: #19367A;
color: #FFFFFF;
font-weight: 600;
.btn-icon {
filter: brightness(0) invert(1);
}
}
&.gift-btn {
background-color: #DE3C4B;
color: #FFFFFF;
font-weight: 500;
.btn-icon {
filter: brightness(0) invert(1);
}
}
}
}
}
/* 赠品状态样式 */
.gift-state {
.img {
width: 160rpx;
height: 160rpx;
margin-bottom: 26rpx;
}
text {
color: #DE3C4B;
font-size: 32rpx;
font-weight: 500;
}
}
}
</style>