Task:抽奖

This commit is contained in:
LinCyJang
2026-05-07 00:10:09 +08:00
parent 91aad660e6
commit 59565871d9
7 changed files with 286 additions and 27 deletions
+1 -1
View File
@@ -1645,7 +1645,7 @@ export default {
(data.isOldUserPopupShow || 0) && (data.isOldUserPopupShow || 0) &&
data.oldUserPopup && data.oldUserPopup &&
data.oldUserPopup.image && data.oldUserPopup.image &&
(data.lotteryCanDraw || false) (data.lotteryCanDraw || false)
) )
this.isDrawPosterVisible = hasDrawPoster this.isDrawPosterVisible = hasDrawPoster
this.isOldUser = !hasDrawPoster && this.canShowOldPoster this.isOldUser = !hasDrawPoster && this.canShowOldPoster
+9 -1
View File
@@ -1514,9 +1514,17 @@ export default {
} }
if(news === 2) { if(news === 2) {
const coupId = that.couponId ? that.couponId : (that.couponList.usable[0] && that.couponList.usable[0].id || '') const coupId = that.couponId ? that.couponId : (that.couponList.usable[0] && that.couponList.usable[0].id || '')
let giftUrl = '/pkg_user/views/gift/gift?cartId=' + res.data.cartId
if (that.storeInfo.discount) {
giftUrl += '&discount=' + that.storeInfo.discount
}
if (that.source === 'countyLottery') {
giftUrl += '&from=countyLottery'
giftUrl += '&drawActivityId=' + Number(that.activityId || 0)
}
uni.navigateTo({ uni.navigateTo({
// + '&couponId=' + coupId // + '&couponId=' + coupId
url: '/pkg_user/views/gift/gift?cartId=' + res.data.cartId + (that.storeInfo.discount ? '&discount=' + that.storeInfo.discount : '') url: giftUrl
}) })
} }
if(news === 0) { if(news === 0) {
+21 -7
View File
@@ -99,14 +99,14 @@
</view> </view>
</view> </view>
<view class="popup-mask" v-if="showSubmitSuccessPopup" @click="closePopup"> <view class="popup-mask" v-if="showSubmitSuccessPopup" @click="confirmSuccess">
<view class="popup-panel success-panel" @click.stop> <view class="popup-panel success-panel" @click.stop>
<view class="popup-close" @click="closePopup">×</view> <view class="popup-close" @click="confirmSuccess">×</view>
<view class="popup-icon-wrap"> <view class="popup-icon-wrap">
<image class="popup-success-icon" :src="webUrl + '/home/qingzhu.png'" mode="aspectFit" /> <image class="popup-success-icon" :src="webUrl + '/home/qingzhu.png'" mode="aspectFit" />
</view> </view>
<view class="popup-title">提交成功</view> <view class="popup-title">提交成功</view>
<view class="popup-desc">奖品将在7个工作日内寄出</view> <view class="popup-desc">奖品将在{{ shipDayText }}个工作日内寄出</view>
<view class="popup-actions"> <view class="popup-actions">
<view class="popup-btn btn-ghost" @click="confirmSuccess">返回</view> <view class="popup-btn btn-ghost" @click="confirmSuccess">返回</view>
<view class="popup-btn btn-confirm" @click="goMyTicket">查看</view> <view class="popup-btn btn-confirm" @click="goMyTicket">查看</view>
@@ -150,6 +150,8 @@ export default {
}, },
showRealnamePopup: false, showRealnamePopup: false,
showSubmitSuccessPopup: false, showSubmitSuccessPopup: false,
shipDay: 7,
prizeOrderId: '',
userInfo: {}, userInfo: {},
realnameStatus: 0, realnameStatus: 0,
waitSubmitAfterRealname: false, waitSubmitAfterRealname: false,
@@ -159,6 +161,11 @@ export default {
computed: { computed: {
prizeImage() { prizeImage() {
return this.form.prizeImage || '' return this.form.prizeImage || ''
},
shipDayText() {
const day = Number(this.shipDay)
if (!day || Number.isNaN(day) || day < 1) return 7
return day
} }
}, },
onLoad(options) { onLoad(options) {
@@ -273,6 +280,8 @@ export default {
return return
} }
await claimCoupon(ticketId) await claimCoupon(ticketId)
this.shipDay = 7
this.prizeOrderId = ''
this.showSubmitSuccessPopup = true this.showSubmitSuccessPopup = true
}, },
async submitPhysicalClaim() { async submitPhysicalClaim() {
@@ -295,7 +304,10 @@ export default {
} }
} }
const addressId = await this.createAddress() const addressId = await this.createAddress()
await claimPrize(ticketId, addressId) const res = await claimPrize(ticketId, addressId)
const data = (res && res.data) || {}
this.shipDay = Number(data.shipDay || 0) || 7
this.prizeOrderId = String(data.orderId || '')
this.waitSubmitAfterRealname = false this.waitSubmitAfterRealname = false
this.showSubmitSuccessPopup = true this.showSubmitSuccessPopup = true
} catch (e) { } catch (e) {
@@ -398,12 +410,14 @@ export default {
}, },
confirmSuccess() { confirmSuccess() {
this.showSubmitSuccessPopup = false this.showSubmitSuccessPopup = false
uni.navigateBack() uni.redirectTo({
url: '/pkg-video/views/county-my-tickets'
})
}, },
goMyTicket() { goMyTicket() {
this.showSubmitSuccessPopup = false this.showSubmitSuccessPopup = false
uni.navigateTo({ uni.redirectTo({
url: '/pkg-video/views/county-my-tickets' url: `/pages/order/OrderDetails/index?id=${this.prizeOrderId}`
}) })
} }
} }
+35 -6
View File
@@ -99,8 +99,14 @@
:key="index" :key="index"
class="goods-item" 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)" /> <image class="goods-image" :src="item.image" mode="aspectFill" @click="goGoodsDetail(item)" />
<view class="goods-name more-t">{{ item.name }}</view> <view class="goods-name more-t">{{ item.storeName }}</view>
<view class="goods-bottom"> <view class="goods-bottom">
<text class="goods-price">{{ item.price }}</text> <text class="goods-price">{{ item.price }}</text>
<view class="goods-cart" @click.stop="openGoodsSku(item)"></view> <view class="goods-cart" @click.stop="openGoodsSku(item)"></view>
@@ -114,7 +120,7 @@
:attr="attr" :attr="attr"
:cartNum="cart_num" :cartNum="cart_num"
:showOk="true" :showOk="true"
okText="立即下单" :okText="currentGoodsItem && Number(currentGoodsItem.isGiftCard) === 1 ? '送给朋友' : '立即下单'"
@changeFun="changeFun" @changeFun="changeFun"
@ok="submitFromSku()" @ok="submitFromSku()"
/> />
@@ -155,7 +161,9 @@ export default {
time: '--:--:--' time: '--:--:--'
}, },
countdownTimer: null, countdownTimer: null,
currentSwiperIndex: 0 currentSwiperIndex: 0,
webUrl: this.$VUE_APP_RESOURCES_URL,
currentGoodsItem: null
} }
}, },
computed: { computed: {
@@ -173,15 +181,18 @@ export default {
return list.map(item => ({ return list.map(item => ({
id: item.productId || item.id || 0, id: item.productId || item.id || 0,
image: item.productImage || item.image || item.pic || '', image: item.productImage || item.image || item.pic || '',
name: item.productName || item.name || item.prizeName || '', storeName: item.storeName || '',
price: item.productPrice || item.price || item.salePrice || 0 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 => ({ return this.prizeList.map(item => ({
id: item.productId || 0, id: item.productId || 0,
image: item.prizeImage || '', image: item.prizeImage || '',
name: item.prizeName || '', name: item.prizeName || '',
price: item.productPrice || item.price || 0 price: item.productPrice || item.price || 0,
isGiftCard: Number(item.isGiftCard || 0)
})) }))
}, },
winnerSortedList() { winnerSortedList() {
@@ -329,11 +340,13 @@ export default {
}, },
openGoodsSku(item) { openGoodsSku(item) {
if (!item.id) return if (!item.id) return
this.currentGoodsItem = item
this.addToCart(item) this.addToCart(item)
}, },
submitFromSku() { submitFromSku() {
const productSelect = this.getAttrItemData(this.attrValue) const productSelect = this.getAttrItemData(this.attrValue)
const currentSelect = productSelect || this.attr.productSelect || {} const currentSelect = productSelect || this.attr.productSelect || {}
const isGiftOrder = Number(this.currentGoodsItem && this.currentGoodsItem.isGiftCard) === 1
const stock = Number(currentSelect.stock || 0) const stock = Number(currentSelect.stock || 0)
const hasNo = (this.attr.productAttr.length && !productSelect && this.isOpen) || stock <= 0 const hasNo = (this.attr.productAttr.length && !productSelect && this.isOpen) || stock <= 0
if (hasNo) { if (hasNo) {
@@ -360,6 +373,12 @@ export default {
this.cart_num = 1 this.cart_num = 1
const cartId = (res.data && res.data.cartId) || '' const cartId = (res.data && res.data.cartId) || ''
if (!cartId) return if (!cartId) return
if (isGiftOrder) {
uni.navigateTo({
url: `/pkg_user/views/gift/gift?cartId=${cartId}&from=countyLottery&drawActivityId=${this.activityId || 0}`
})
return
}
uni.navigateTo({ uni.navigateTo({
url: `/pages/order/OrderSubmission/index?id=${cartId}` url: `/pages/order/OrderSubmission/index?id=${cartId}`
}) })
@@ -786,6 +805,16 @@ export default {
width: 316rpx; width: 316rpx;
background: #fff; background: #fff;
margin-bottom: 30rpx; margin-bottom: 30rpx;
position: relative;
.goods-gift-tag {
position: absolute;
left: 0;
top: 0;
width: 120rpx;
z-index: 2;
pointer-events: none;
}
.goods-image { .goods-image {
width: 100%; width: 100%;
+99 -7
View File
@@ -25,9 +25,31 @@
</view> --> </view> -->
<scroll-view class="page-body" scroll-y> <scroll-view class="page-body" scroll-y>
<view class="tip-bar" v-if="summaryText"> <view class="tip-bar">
<view class="tip-text one-t">{{ summaryText }}</view> <view class="tip-text" v-if="!winnerSortedList.length">暂时无人中奖</view>
<view class="tip-btn" @click="goWinnersPage">查看全部 <text class="icon-expand"></text></view> <view class="tip-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="tip-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="tip-btn" @click="goWinnersPage">查看全部 <text class="icon-expand"></text></view>
</view> </view>
<view class="ticket-list" v-if="displayList.length"> <view class="ticket-list" v-if="displayList.length">
@@ -56,7 +78,7 @@
<view class="ticket-footer" v-if="item.status === 1"> <view class="ticket-footer" v-if="item.status === 1">
<template v-if="item.claimStatus === 0"> <template v-if="item.claimStatus === 0">
<view class="footer-note">注意请在7天内领取过期不予发放</view> <view class="footer-note">注意请在{{ getClaimDaysText(item) }}内领取过期不予发放</view>
<view class="footer-btn btn-claim" @click="onClaim(item)"> </view> <view class="footer-btn btn-claim" @click="onClaim(item)"> </view>
</template> </template>
<template v-else-if="item.claimStatus === 1"> <template v-else-if="item.claimStatus === 1">
@@ -91,7 +113,7 @@
</template> </template>
<script> <script>
import { claimCoupon, getDrawMyTickets } from '@/api/lottery' import { claimCoupon, getDrawLatestWinners, getDrawMyTickets } from '@/api/lottery'
export default { export default {
name: 'CountyMyTicketsPage', name: 'CountyMyTicketsPage',
@@ -110,6 +132,7 @@ export default {
], ],
list: [], list: [],
openedList: [], openedList: [],
latestWinnerList: [],
showCouponSuccessPopup: false, showCouponSuccessPopup: false,
claiming: false claiming: false
} }
@@ -118,8 +141,15 @@ export default {
displayList() { displayList() {
return this.activeTab === 'opened' ? this.openedList : this.list return this.activeTab === 'opened' ? this.openedList : this.list
}, },
summaryText() { winnerSortedList() {
return `恭喜海*在第01期抽奖活动中获得 iPhone17 pro 手机` 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))
} }
}, },
onLoad(options) { onLoad(options) {
@@ -129,9 +159,28 @@ export default {
}, },
onShow() { onShow() {
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 20 this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 20
this.fetchLatestWinners()
this.fetchList() this.fetchList()
}, },
methods: { methods: {
getPeriodNoValue(periodNo) {
const text = String(periodNo || '')
const match = text.match(/\d+/g)
if (!match || !match.length) return 0
return Number(match.join('')) || 0
},
async fetchLatestWinners() {
try {
const res = await getDrawLatestWinners()
const winnersData = res && res.data
const list = Array.isArray(winnersData)
? winnersData
: (Array.isArray(winnersData && winnersData.list) ? winnersData.list : [])
this.latestWinnerList = list
} catch (e) {
this.latestWinnerList = []
}
},
mapTabToStatus(tab) { mapTabToStatus(tab) {
const map = { const map = {
wait: 0, wait: 0,
@@ -158,6 +207,7 @@ export default {
claimStatus: Number.isNaN(claimStatusNum) ? 0 : claimStatusNum, claimStatus: Number.isNaN(claimStatusNum) ? 0 : claimStatusNum,
sourceOrderId: item.sourceOrderId || item.orderId || item.orderNo || '', sourceOrderId: item.sourceOrderId || item.orderId || item.orderNo || '',
drawTime: item.drawTime || item.openTime || '', drawTime: item.drawTime || item.openTime || '',
claimDeadline: item.claimDeadline || '',
prizeName: item.prizeName || item.awardName || '', prizeName: item.prizeName || item.awardName || '',
prizeType: item.prizeType || item.awardType || '', prizeType: item.prizeType || item.awardType || '',
prizeTypeName: item.prizeTypeName || item.awardTypeName || '' prizeTypeName: item.prizeTypeName || item.awardTypeName || ''
@@ -241,6 +291,34 @@ export default {
const mm = String(date.getMinutes()).padStart(2, '0') const mm = String(date.getMinutes()).padStart(2, '0')
return `${y}${m}${d}${hh}:${mm}` return `${y}${m}${d}${hh}:${mm}`
}, },
formatDateTime(time) {
if (!time) return '--'
const text = String(time).trim()
const date = new Date(text.replace(/-/g, '/'))
if (Number.isNaN(date.getTime())) return text
const y = date.getFullYear()
const m = String(date.getMonth() + 1).padStart(2, '0')
const d = String(date.getDate()).padStart(2, '0')
const hh = String(date.getHours()).padStart(2, '0')
const mm = String(date.getMinutes()).padStart(2, '0')
const ss = String(date.getSeconds()).padStart(2, '0')
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
},
getClaimDeadlineText(item = {}) {
return this.formatDateTime(item.claimDeadline || '')
},
getClaimDaysText(item = {}) {
const drawTime = String(item.drawTime || '').trim()
const claimDeadline = String(item.claimDeadline || '').trim()
if (!drawTime || !claimDeadline) return '--'
const drawDate = new Date(drawTime.replace(/-/g, '/'))
const deadlineDate = new Date(claimDeadline.replace(/-/g, '/'))
if (Number.isNaN(drawDate.getTime()) || Number.isNaN(deadlineDate.getTime())) return '--'
const diff = deadlineDate.getTime() - drawDate.getTime()
if (diff <= 0) return '0天'
const days = Math.ceil(diff / (24 * 60 * 60 * 1000))
return `${days}`
},
async onClaim(item) { async onClaim(item) {
if (!item.id) return if (!item.id) return
if (this.claiming) return if (this.claiming) return
@@ -428,6 +506,20 @@ export default {
flex: 1; flex: 1;
font-weight: 500; font-weight: 500;
color: #333; color: #333;
.blue {
color: #3b7cf6;
}
.red {
color: #cb302c;
}
}
.winner-swiper {
flex: 1;
height: 36rpx;
margin-right: 8rpx;
} }
.tip-btn { .tip-btn {
+4 -2
View File
@@ -80,7 +80,7 @@
<button v-else class="my-tickets-btn" @click="navToMyTickets"> <button v-else class="my-tickets-btn" @click="navToMyTickets">
<text class="btn-text">我的抽奖码</text> <text class="btn-text">我的抽奖码</text>
</button> </button>
<view class="claim-tip">*请在7天内领取过期失效</view> <view class="claim-tip">*请在{{ remainingClaimDays }}天内领取过期失效</view>
</view> </view>
</view> </view>
@@ -180,7 +180,8 @@ export default {
showCouponSuccessPopup: false, showCouponSuccessPopup: false,
showHistory: false, showHistory: false,
entryWithoutActivityId: false, entryWithoutActivityId: false,
historyList: [] historyList: [],
remainingClaimDays: 7
} }
}, },
onLoad(options) { onLoad(options) {
@@ -364,6 +365,7 @@ export default {
this.userWinList = this.mapUserWinList(filteredMyTicketList) this.userWinList = this.mapUserWinList(filteredMyTicketList)
this.hasWon = this.userWinList.length > 0 ? 1 : 0 this.hasWon = this.userWinList.length > 0 ? 1 : 0
this.periodLabel = winnerData.periodNo || "01" this.periodLabel = winnerData.periodNo || "01"
this.remainingClaimDays = winnerData.remainingClaimDays || 7
} catch (e) { } catch (e) {
uni.showToast({ uni.showToast({
title: "中奖数据加载失败", title: "中奖数据加载失败",
+117 -3
View File
@@ -180,6 +180,28 @@
:show-tab="false" :show-tab="false"
/> />
</u-popup> </u-popup>
<u-popup
:show="showLotteryGiftPopup"
:round="40"
mode="center"
:close-on-click-overlay="false"
bgColor="transparent"
>
<view class="lottery-gift-popup">
<view class="lottery-gift-close" @click="closeLotteryGiftPopup">
<u-icon name="close-circle" color="#111" size="24"></u-icon>
</view>
<view class="lottery-gift-icon-wrap">
<image class="ticket-icon-check" :src="webUrl + '/home/gongxi.png'" mode="widthFix"></image>
</view>
<view class="lottery-gift-title">支付成功</view>
<view class="lottery-gift-content">好友领取礼包后您才可以获得<br>抽奖码哦~</view>
<view class="lottery-gift-actions">
<button class="lottery-gift-btn home-btn" @click="goHomeFromLotteryPopup">返回首页</button>
<button open-type="share" class="lottery-gift-btn send" @click="closeLotteryGiftPopup">送给朋友</button>
</view>
</view>
</u-popup>
</view> </view>
</template> </template>
@@ -251,7 +273,9 @@ export default {
blindImage: '', blindImage: '',
isGroupBuy: false, isGroupBuy: false,
popupCover: '', popupCover: '',
showInput: true showInput: true,
isCountyLotteryGift: false,
showLotteryGiftPopup: false
} }
}, },
watch: { watch: {
@@ -268,6 +292,7 @@ export default {
onLoad(opts) { onLoad(opts) {
this.cartId = opts.cartId this.cartId = opts.cartId
this.isGroupBuy = opts.isGroupBuy === '1' this.isGroupBuy = opts.isGroupBuy === '1'
this.isCountyLotteryGift = opts.from === 'countyLottery' || opts.isCountyLotteryGift === '1' || !!opts.drawActivityId
// this.couponId = opts.couponId || 0 // this.couponId = opts.couponId || 0
this.discount = opts.discount this.discount = opts.discount
if(this.isGroupBuy) { if(this.isGroupBuy) {
@@ -485,6 +510,21 @@ export default {
this.loading = false this.loading = false
}) })
}, },
handleGiftPaySuccess() {
this.isPayOk = true
if (this.isCountyLotteryGift) {
this.showLotteryGiftPopup = true
}
},
closeLotteryGiftPopup() {
this.showLotteryGiftPopup = false
},
goHomeFromLotteryPopup() {
this.showLotteryGiftPopup = false
uni.switchTab({
url: '/pages/home/index'
})
},
/** /**
* 确认赠送 * 确认赠送
* @param {*} * @param {*}
@@ -575,7 +615,7 @@ export default {
icon: "none", icon: "none",
duration: 2000 duration: 2000
}); });
this.isPayOk = true; this.handleGiftPaySuccess();
break; break;
case "WECHAT_H5_PAY": case "WECHAT_H5_PAY":
// H5支付 // H5支付
@@ -592,7 +632,7 @@ export default {
icon: "none", icon: "none",
duration: 2000 duration: 2000
}); });
this.isPayOk = true; this.handleGiftPaySuccess();
}).catch(err => { }).catch(err => {
// this.makeAgain() // this.makeAgain()
@@ -798,4 +838,78 @@ export default {
width: 100%; width: 100%;
border-radius: 16rpx; border-radius: 16rpx;
} }
.lottery-gift-popup{
background: #fff;
border-radius: 40rpx;
padding: 60rpx 40rpx 50rpx;
position: relative;
box-sizing: border-box;
width: 550rpx;
height: 560rpx;
}
.lottery-gift-close{
position: absolute;
top: 30rpx;
right: 30rpx;
z-index: 10;
}
.lottery-gift-icon-wrap{
display: flex;
justify-content: center;
margin-bottom: 30rpx;
}
.ticket-icon-check{
width: 100rpx;
height: 100rpx;
margin-top: 10rpx;
}
.lottery-gift-title{
text-align: center;
font-size: 48rpx;
font-weight: bold;
color: #333;
margin-bottom: 30rpx;
}
.lottery-gift-content{
text-align: center;
color: #999;
font-size: 28rpx;
line-height: 1.6;
}
.lottery-gift-actions{
margin-top: 60rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.lottery-gift-btn{
width: 240rpx;
height: 80rpx;
line-height: 76rpx; /* 微调行高补偿边框 */
border-radius: 40rpx;
text-align: center;
font-size: 32rpx;
font-weight: 500;
box-sizing: border-box;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
}
.lottery-gift-btn.home-btn{
border: 2rpx solid #c52733;
color: #c52733;
background: #fff;
}
.lottery-gift-btn.send{
border: 2rpx solid #c52733;
color: #fff;
background: #c52733;
padding: 0;
margin-left: 20rpx;
}
.lottery-gift-btn.send::after{
border: none;
}
</style> </style>