Files
xdd-uniapp-new/pkg-video/views/county-lottery.vue
T

898 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="county-lottery-page">
<view class="banner-wrapper">
<view class="top-banner" :style="topBannerStyle">
<view class="banner-content">
<view class="banner-date">开奖时间{{ openDateText }}</view>
<view class="banner-countdown">
<text class="text">距离开奖还有</text>
<text class="num">{{ countdownData.day }}</text>
<text class="text"></text>
<text class="num">{{ countdownData.time }}</text>
</view>
</view>
</view>
</view>
<view class="side-entry rules" @click="openRulesModel">活动规则</view>
<view class="side-entry mine" @click="navToLog">我的抽奖码</view>
<view class="winners-wrap">
<view class="winners-text" v-if="!winnerSortedList.length">暂时无人中奖</view>
<view class="winners-text one-t" v-else-if="winnerSortedList.length === 1">
恭喜 <text class="blue">{{ winnerSortedList[0].name }}</text>
在第 <text class="blue">{{ winnerSortedList[0].periodNo }}</text> 期抽奖活动中获得
<text class="red">{{ winnerSortedList[0].prizeName }}</text>
</view>
<swiper
v-else
class="winner-swiper"
vertical
circular
autoplay
:interval="3000"
:duration="500"
>
<swiper-item v-for="(winner, index) in winnerSortedList" :key="index">
<view class="winners-text one-t">
恭喜 <text class="blue">{{ winner.name }}</text>
在第 <text class="blue">{{ winner.periodNo }}</text> 期抽奖活动中获得
<text class="red">{{ winner.prizeName }}</text>
</view>
</swiper-item>
</swiper>
<view class="winners-btn" @click="navToWinners">查看全部 <text class="arrow"></text></view>
</view>
<view class="pool-wrap">
<view class="pool-header" style="background: linear-gradient(to bottom, #fff 50%, #CB302C 50%);">
<view class="pool-title-wrap">
<view class="pool-title">奖品池 <text class="sub">/ prize pool</text></view>
</view>
<view class="pool-desc">实付满{{ buyThresholdText }}元即可获得抽奖码定时统一开奖</view>
</view>
<view class="pool-body">
<swiper
class="pool-swiper"
:autoplay="prizeList.length > 1"
:circular="prizeList.length > 1"
:interval="3000"
:duration="500"
previous-margin="220rpx"
next-margin="220rpx"
@change="onSwiperChange"
v-if="prizeList.length"
>
<swiper-item v-for="(prize, gIndex) in prizeList" :key="gIndex">
<view class="pool-list-group">
<view
class="pool-item"
:class="{ 'is-active': currentSwiperIndex === gIndex }"
style="margin: 0 auto;"
>
<view class="item-inner">
<view class="item-dashed">
<image class="pool-image" :src="prize.prizeImage" mode="aspectFit" />
</view>
</view>
<image class="prize-tag" :src="prize.levelIcon" v-if="prize.levelIcon" mode="aspectFit" />
<view class="pool-name-wrap">
<view class="pool-name one-t">{{ prize.prizeName }}</view>
</view>
</view>
</view>
</swiper-item>
</swiper>
</view>
</view>
<view class="goods-section">
<view class="goods-header-box">
<view class="goods-title-pill">
<view style="background: #ffb611;
padding: 8rpx 40rpx;
border-radius: 40rpx;"><text class="dot">·</text> 活动商品 <text class="dot">·</text></view>
</view>
<view class="goods-sub">—— 购买即得抽奖码 ——</view>
</view>
<view class="goods-list">
<view
v-for="(item, index) in activityGoodsList"
:key="index"
class="goods-item"
>
<image
v-if="Number(item.isGiftCard) === 1"
class="goods-gift-tag"
:src="webUrl + '/home/gift-tag.png'"
mode="widthFix"
/>
<image class="goods-image" :src="item.image" mode="aspectFill" @click="goGoodsDetail(item)" />
<view class="goods-name more-t">{{ item.storeName }}</view>
<view class="goods-bottom">
<text class="goods-price">{{ item.price }}</text>
<view class="goods-cart" @click.stop="openGoodsSku(item)"></view>
</view>
</view>
</view>
</view>
<ProductWindow
ref="attrWindow"
:attr="attr"
:cartNum="cart_num"
:showOk="true"
:okText="currentGoodsItem && Number(currentGoodsItem.isGiftCard) === 1 ? '送给朋友' : '立即下单'"
@changeFun="changeFun"
@ok="submitFromSku()"
/>
</view>
</template>
<script>
import { getDrawActivityInfo, getDrawLatestWinners } from '@/api/lottery'
import { postCartAdd } from '@/api/store'
import ProductWindow from '@/components/ProductWindow'
import goCartMixin from '@/mixins/goCartMixins'
import { pageListenMixins } from '@/mixins/pageListenMixins'
export default {
name: 'CountyLotteryPage',
components: {
ProductWindow
},
mixins: [pageListenMixins, goCartMixin],
data() {
return {
ready: false,
activityInfo: {
drawImage: '',
drawTime: '',
winnerList: [],
prizePool: [],
products: []
},
latestWinnerList: [],
activityId: 0,
onlyOneToAddCart: false,
statusBarHeight: 20,
countdownData: {
day: '--',
time: '--:--:--'
},
countdownTimer: null,
currentSwiperIndex: 0,
webUrl: this.$VUE_APP_RESOURCES_URL,
currentGoodsItem: null
}
},
computed: {
topBannerStyle() {
const drawImage = String(this.activityInfo.drawImage || '').trim()
if (!drawImage) return ''
return `background-image:url(${drawImage});background-size:100% 100%;background-repeat:no-repeat;background-position:center top;`
},
prizeList() {
return this.activityInfo.prizePool || []
},
activityGoodsList() {
const list = this.activityInfo.products || []
if (list.length > 0) {
return list.map(item => ({
id: item.productId || item.id || 0,
image: item.productImage || item.image || item.pic || '',
storeName: item.storeName || '',
productName: item.productName || item.name || item.prizeName || '',
price: item.productPrice || item.price || item.salePrice || 0,
isGiftCard: Number(item.isGiftCard || 0)
}))
}
return this.prizeList.map(item => ({
id: item.productId || 0,
image: item.prizeImage || '',
name: item.prizeName || '',
price: item.productPrice || item.price || 0,
isGiftCard: Number(item.isGiftCard || 0)
}))
},
winnerSortedList() {
const list = this.latestWinnerList || []
if (!list.length) return []
const mapped = list.map(item => ({
name: item.realName || item.phone || '用户',
periodNo: item.periodNo || '-',
prizeName: item.prizeName || '神秘奖品'
}))
return mapped.sort((a, b) => this.getPeriodNoValue(b.periodNo) - this.getPeriodNoValue(a.periodNo))
},
buyThresholdText() {
const spendThreshold = this.activityInfo.spendThreshold || 0
return spendThreshold
},
openDateText() {
const target = this.getTargetDate()
if (!target) return '--'
const year = target.getFullYear()
const month = String(target.getMonth() + 1).padStart(2, '0')
const day = String(target.getDate()).padStart(2, '0')
return `${year}${month}${day}日`
}
},
onLoad(options) {
this.activityId = Number(options.activityId || options.areaId) || 0
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 20
this.init()
},
onUnload() {
this.clearCountdownTimer()
},
methods: {
init() {
if (!this.activityId) {
uni.showToast({
title: '缺少活动ID',
icon: 'none'
})
return
}
Promise.all([
getDrawActivityInfo(this.activityId),
getDrawLatestWinners()
]).then(([activityRes, winnersRes]) => {
if (activityRes && activityRes.success) {
const data = activityRes.data || {}
// 如果活动已开奖(或已过开奖时间),直接重定向至中奖名单页
const targetTime = data.drawTime || ''
let isPassed = false
if (targetTime) {
const date = new Date(String(targetTime).replace(/-/g, '/'))
if (!Number.isNaN(date.getTime()) && date.getTime() <= Date.now()) {
isPassed = true
}
}
if (isPassed || Number(data.status) === 2 || Number(data.status) === 3) {
uni.redirectTo({ url: `/pkg-video/views/county-winners?activityId=${this.activityId}` })
return
}
this.activityInfo = {
...this.activityInfo,
...data,
drawImage: data.drawImage || ''
}
this.ready = true
this.startCountdown()
}
const winnersData = winnersRes && winnersRes.data
const list = Array.isArray(winnersData)
? winnersData
: (Array.isArray(winnersData && winnersData.list) ? winnersData.list : [])
this.latestWinnerList = list
})
},
getTargetDate() {
const targetTime = this.activityInfo.drawTime || ''
if (!targetTime) return null
const date = new Date(String(targetTime).replace(/-/g, '/'))
if (Number.isNaN(date.getTime())) return null
return date
},
startCountdown() {
this.clearCountdownTimer()
const calc = () => {
const target = this.getTargetDate()
if (!target) {
this.countdownData = { day: '--', time: '--:--:--' }
return
}
let diff = target.getTime() - Date.now()
if (diff <= 0) {
this.countdownData = { day: '00', time: '00:00:00' }
return
}
const day = Math.floor(diff / (24 * 60 * 60 * 1000))
diff -= day * 24 * 60 * 60 * 1000
const hour = Math.floor(diff / (60 * 60 * 1000))
diff -= hour * 60 * 60 * 1000
const minute = Math.floor(diff / (60 * 1000))
diff -= minute * 60 * 1000
const second = Math.floor(diff / 1000)
const dd = String(day).padStart(2, '0')
const hh = String(hour).padStart(2, '0')
const mm = String(minute).padStart(2, '0')
const ss = String(second).padStart(2, '0')
this.countdownData = {
day: dd,
time: `${hh}:${mm}:${ss}`
}
}
calc()
this.countdownTimer = setInterval(calc, 1000)
},
clearCountdownTimer() {
if (this.countdownTimer) {
clearInterval(this.countdownTimer)
this.countdownTimer = null
}
},
getPeriodNoValue(periodNo) {
const text = String(periodNo || '')
const match = text.match(/\d+/g)
if (!match || !match.length) return 0
return Number(match.join('')) || 0
},
openRulesModel() {
uni.navigateTo({ url: '/pkg-video/views/county-lottery-rules' })
},
navToWinners() {
const targetDate = this.getTargetDate()
const isNotOpened = targetDate && targetDate.getTime() > Date.now()
const url = isNotOpened
? '/pkg-video/views/county-winners'
: `/pkg-video/views/county-winners?activityId=${this.activityId}`
uni.navigateTo({ url })
},
navToLog() {
uni.navigateTo({ url: '/pkg-video/views/county-my-tickets' })
},
goBack() {
if (getCurrentPages().length > 1) {
uni.navigateBack()
return
}
uni.switchTab({
url: '/pages/home/index'
})
},
onSwiperChange(e) {
this.currentSwiperIndex = e.detail.current
},
goGoodsDetail(item) {
if (!item.id) return
uni.navigateTo({ url: `/pages/shop/GoodsCon/index?id=${item.id}&from=countyLottery&activityId=${this.activityId}` })
},
openGoodsSku(item) {
if (!item.id) return
this.currentGoodsItem = item
this.addToCart(item)
},
submitFromSku() {
const productSelect = this.getAttrItemData(this.attrValue)
const currentSelect = productSelect || this.attr.productSelect || {}
const isGiftOrder = Number(this.currentGoodsItem && this.currentGoodsItem.isGiftCard) === 1
const stock = Number(currentSelect.stock || 0)
const hasNo = (this.attr.productAttr.length && !productSelect && this.isOpen) || stock <= 0
if (hasNo) {
uni.showToast({
title: '产品库存不足,请选择其他商品',
icon: 'none',
duration: 3000
})
return
}
const q = {
productId: this.m_id,
cartNum: Number(currentSelect.cart_num || 1),
new: 1,
uniqueId: currentSelect.unique || ''
}
if (this.activityId) {
q.drawActivityId = Number(this.activityId)
}
postCartAdd(q).then(res => {
this.isOpen = false
this.attr.cartAttr = false
this.$set(this.attr.productSelect, 'cart_num', 1)
this.cart_num = 1
const cartId = (res.data && res.data.cartId) || ''
if (!cartId) return
if (isGiftOrder) {
uni.navigateTo({
url: `/pkg_user/views/gift/gift?cartId=${cartId}&from=countyLottery&drawActivityId=${this.activityId || 0}`
})
return
}
uni.navigateTo({
url: `/pages/order/OrderSubmission/index?id=${cartId}`
})
})
}
}
}
</script>
<style scoped lang="less">
.county-lottery-page {
min-height: 100vh;
background-color: #f5f5f5;
padding-bottom: 40rpx;
}
.custom-header {
position: fixed;
left: 0;
top: 0;
width: 100%;
z-index: 30;
background: rgba(255, 255, 255, 0);
}
.custom-header-inner {
height: 88rpx;
display: flex;
align-items: center;
padding: 0 24rpx;
}
.header-back {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
background: rgba(0, 0, 0, .35);
display: flex;
align-items: center;
justify-content: center;
}
.header-back-icon {
color: #fff;
font-size: 56rpx;
line-height: 1;
margin-top: -6rpx;
}
.banner-wrapper {
position: relative;
background: #f5f5f5;
padding-bottom: 30rpx;
}
.banner-red-curve {
background: #cb302c;
height: 40rpx;
position: absolute;
bottom: 0;
left: 0;
width: 100%;
border-bottom-left-radius: 60rpx;
border-bottom-right-radius: 60rpx;
z-index: 1;
}
.top-banner {
background-color: #ffb611;
background-size: 100% 100%;
background-repeat: no-repeat;
height: 640rpx;
position: relative;
border-bottom-left-radius: 40rpx;
border-bottom-right-radius: 40rpx;
z-index: 2;
}
.banner-content {
position: absolute;
bottom: 40rpx;
left: 0;
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
.banner-date {
position: relative;
background: #3b7cf6;
color: #fff;
border: 4rpx solid #fff;
border-radius: 40rpx;
padding: 6rpx 30rpx;
font-size: 24rpx;
margin-bottom: 24rpx;
&::after {
content: '';
position: absolute;
bottom: -14rpx;
left: 50%;
transform: translateX(-50%);
border-width: 14rpx 14rpx 0;
border-style: solid;
border-color: #fff transparent transparent transparent;
}
&::before {
content: '';
position: absolute;
bottom: -8rpx;
left: 50%;
transform: translateX(-50%);
border-width: 10rpx 10rpx 0;
border-style: solid;
border-color: #3b7cf6 transparent transparent transparent;
z-index: 1;
}
}
.banner-countdown {
background: #cb302c;
color: #fff;
border: 6rpx solid #fff;
border-radius: 60rpx;
padding: 10rpx 40rpx;
display: flex;
align-items: baseline;
box-shadow: inset 0 0 0 6rpx rgba(0, 0, 0, 0.1);
.text {
font-size: 48rpx;
}
.num {
font-size: 48rpx;
font-weight: bold;
margin: 0 10rpx;
}
}
.side-entry {
position: fixed;
right: 0;
background: #fff;
color: #333;
font-size: 24rpx;
width: 44rpx;
padding: 24rpx 0;
text-align: center;
border-radius: 24rpx 24rpx 0 24rpx;
z-index: 10;
writing-mode: vertical-rl;
letter-spacing: 6rpx;
font-weight: bold;
box-shadow: -2rpx 2rpx 8rpx rgba(0, 0, 0, 0.1);
line-height: 44rpx;
&::after{
content: '';
position: absolute;
bottom: -12rpx;
right: 0; /* 修改为对齐右侧,以匹配侧边栏的布局 */
width: 0;
height: 0;
border-width: 14rpx 0 0 14rpx; /* 将三角形反转:顶部和左侧保留宽度,形成一个斜边向右下的直角三角形 */
border-style: solid;
border-color: #fff transparent transparent transparent; /* 顶部为白色 */
}
}
.side-entry.rules {
top: 60rpx;
}
.side-entry.mine {
top: 260rpx;
}
.winners-wrap {
margin: 0 24rpx;
background: #fff;
border-radius: 40rpx;
padding: 0rpx 0rpx 0rpx 30rpx;
display: flex;
align-items: center;
justify-content: space-between;
border: 2rpx solid #333;
.winners-text {
font-size: 24rpx;
color: #333;
flex: 1;
.blue {
color: #3b7cf6;
}
.red {
color: #cb302c;
}
}
.winner-swiper {
flex: 1;
height: 36rpx;
margin-right: 8rpx;
margin-top: 4rpx;
}
.winners-btn {
background: #3b7cf6;
color: #fff;
font-size: 24rpx;
padding: 16rpx 20rpx;
border-radius: 30rpx;
display: flex;
align-items: center;
white-space: nowrap;
margin-left: 16rpx;
.arrow {
margin-left: 4rpx;
font-size: 22rpx;
}
}
}
.pool-wrap {
margin: 24rpx;
background: #cb302c;
border-radius: 40rpx;
overflow: hidden;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
.pool-header {
display: flex;
align-items: stretch;
.pool-title-wrap{
background: #CB302C;
border-top-right-radius: 40rpx;
position: relative;
}
.pool-title {
background: #ffb611;
color: #333;
font-weight: bold;
font-size: 34rpx;
padding: 10rpx 14rpx;
border-radius: 40rpx;
margin: 10rpx;
display: flex;
align-items: baseline;
position: relative;
.sub {
font-size: 20rpx;
font-weight: bold;
margin-left: 8rpx;
}
}
.pool-desc {
font-size: 24rpx;
color: #666;
flex: 1;
background: #fff;
display: flex;
align-items: center;
padding: 0 20rpx 0 30rpx;
border-bottom-left-radius: 40rpx;
}
}
.pool-body {
padding: 30rpx 0 40rpx 20rpx;
}
.pool-swiper {
height: 340rpx; /* 增加高度防止放大后被裁剪,并留出阴影和标签的空间 */
width: 100%;
}
.pool-list-group {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
padding: 0;
}
.pool-item {
width: 220rpx; /* 恢复正常大小 */
margin: 0 auto;
position: relative;
flex-shrink: 0;
transform: scale(0.85); /* 默认两侧缩小 */
transition: transform 0.3s ease;
color: #333;
&.is-active {
transform: scale(1.1); /* 当前项放大 */
z-index: 10;
color: #cb302c;
}
.item-inner {
background: #fff;
border-radius: 16rpx 48rpx 16rpx 16rpx;
padding: 12rpx;
height: 270rpx;
box-sizing: border-box;
border: 10rpx solid #ffb611;
border-bottom-width: 60rpx;
// box-shadow: 10rpx 10rpx 0 #ffb611;
.item-dashed {
// border: 2rpx dashed #ccc;
border-radius: 8rpx 36rpx 8rpx 8rpx;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
.pool-image {
width: 150rpx;
height: 150rpx;
}
}
}
.prize-tag {
position: absolute;
left: -10rpx;
bottom: 20rpx;
width: 76rpx;
height: 76rpx;
z-index: 2;
}
.pool-name-wrap {
position: absolute;
bottom: 10rpx;
right: -10rpx;
z-index: 3;
max-width: 70%;
&::after {
content: '';
position: absolute;
top: -10rpx;
right: 0;
width: 0;
height: 0;
border-bottom: 10rpx solid #A19669;
border-right: 10rpx solid transparent;
}
.pool-name {
background: #fff;
font-size: 22rpx;
font-weight: bold;
padding: 6rpx 10rpx;
border-radius: 30rpx 0 0 30rpx;
text-align: center;
}
}
}
}
.goods-section {
margin: 60rpx 24rpx 24rpx;
background: #fff;
border-radius: 24rpx;
position: relative;
box-shadow: 0 4rpx 12rpx rgba(0, 0, 0, 0.05);
.goods-header-box {
background: #cb302c;
border-radius: 24rpx 24rpx 0 0;
padding: 50rpx 0 20rpx;
display: flex;
flex-direction: column;
align-items: center;
position: relative;
.goods-title-pill {
position: absolute;
top: -34rpx;
left: 50%;
transform: translateX(-50%);
background: #ffb611;
color: #333;
font-size: 32rpx;
font-weight: bold;
border-radius: 40rpx;
border: 6rpx solid #fff;
display: flex;
align-items: center;
white-space: nowrap;
box-shadow: 0 -6rpx 0 #CB302C;
.dot {
margin: 0 8rpx;
}
&::after {
content: '';
position: absolute;
bottom: -16rpx;
left: 50%;
transform: translateX(-50%) rotate(-45deg);
width: 30rpx;
height: 30rpx;
border: 6rpx solid #fff;
background: #ffb611;
/* 为了不让这个三角形的边框跑到上方的背景前,可以设置层级或者利用边框隐藏等,目前看原来的效果是直接叠加在底下的。
由于要模拟原本的 .triangle 元素层级,我们用 z-index: -1 把它垫在 pill 下面即可 */
z-index: -1;
}
}
.goods-sub {
color: #fff;
font-size: 24rpx;
font-weight: 500;
}
}
.goods-list {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
padding: 24rpx;
}
.goods-item {
width: 316rpx;
background: #fff;
margin-bottom: 30rpx;
position: relative;
.goods-gift-tag {
position: absolute;
left: 0;
top: 0;
width: 120rpx;
z-index: 2;
pointer-events: none;
}
.goods-image {
width: 100%;
height: 316rpx;
background: #f8f8f8;
border-radius: 16rpx;
}
.goods-name {
font-size: 26rpx;
color: #333;
line-height: 1.4;
margin: 16rpx 0;
height: 72rpx;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
}
.goods-bottom {
display: flex;
align-items: center;
justify-content: space-between;
.goods-price {
color: #cb302c;
font-size: 32rpx;
font-weight: bold;
}
.goods-cart {
width: 48rpx;
height: 48rpx;
background-color: #cb302c;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='white'%3E%3Cpath d='M7 18c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zM1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2H1zm16 16c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2z'/%3E%3C/svg%3E");
background-size: 28rpx 28rpx;
background-repeat: no-repeat;
background-position: center;
color: transparent;
}
}
}
}
</style>