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

729 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="winners-page">
<view class="custom-header" :style="{ paddingTop: `${statusBarHeight}px` }">
<view class="header-inner">
<view class="header-back" @click="goBack">
<text class="header-back-icon"></text>
</view>
<view class="header-title">中奖名单</view>
</view>
</view>
<view class="content-wrap" v-if="loaded">
<view class="draw-info-wrap" :style="{ backgroundImage: `url(${webUrl}/zhongjiang5.png)` }">
<view class="period-side left">
<text class="side-text"></text>
<text class="side-text">{{ periodLabel }}</text>
<text class="side-text"></text>
</view>
<view class="period-side right">
<view class="side-text side-text-count">
<text></text>
<text></text>
<text></text>
<text></text>
<text></text>
<text></text>
</view>
</view>
<view class="draw-main">
<view class="draw-title">本期已开奖</view>
<view class="draw-time">开奖时间{{ drawTime }}</view>
</view>
</view>
<view class="win-banner" v-if="hasWon === 1 && userWinList.length > 0" :style="{ backgroundImage: `url(${webUrl}/zhongjiangn.png)` }">
<view class="win-banner-subtitle">
您的抽奖码 <text class="code">{{ userWinList[0].ticketCode }}</text> 获得了
</view>
<view class="prize-card" v-for="(prize, index) in userWinList" :key="index">
<view class="prize-img-wrap">
<image class="prize-img" :src="prize.prizeImage" mode="aspectFill"></image>
</view>
<view class="prize-info">
<view class="prize-name-wrap">
<text class="prize-level">{{ prize.levelName }}</text>
<text class="prize-name">{{ prize.prizeName }}</text>
</view>
<view class="prize-desc">{{ prize.prizeDesc || "默认" }}</view>
</view>
</view>
<button class="my-tickets-btn" @click="handleClaimNow">
<text class="btn-text">立即领取</text>
</button>
<view class="claim-tip">*请在7天内领取过期失效</view>
</view>
<view class="winners-list-wrap">
<view class="list-title-badge" :style="{ backgroundImage: `url(${webUrl}/zhongjiang6.png)` }">
<text class="gift-icon" style="opacity: 0;">🎁</text>
<text class="title-text" style="opacity: 0;">中奖名单</text>
</view>
<view class="list-content">
<view class="list-item" v-for="(item, index) in activityWinnerList" :key="index">
<view class="item-left">
<view class="item-prize">
<text class="level">{{ item.levelName }}</text>
<text class="name">{{ item.prizeName }}</text>
</view>
<view class="item-code">
中奖码<text class="code-text">{{ item.ticketCode }}</text>
</view>
</view>
<view class="item-right">
<view class="user-name">{{ item.realName }}</view>
<view class="user-phone">{{ item.phone }}</view>
</view>
</view>
<view class="empty-text" v-if="activityWinnerList.length === 0">暂无中奖名单</view>
</view>
</view>
</view>
<view class="coupon-popup-mask" v-if="showCouponSuccessPopup" @click="closeCouponSuccessPopup">
<view class="coupon-popup" @click.stop>
<view class="popup-close" @click="closeCouponSuccessPopup">×</view>
<view class="popup-icon-wrap">
<text class="popup-icon">🎉</text>
</view>
<view class="popup-title">领取成功</view>
<view class="popup-desc">您的奖品已经领取成功请前往我的优惠券查看详情</view>
<view class="popup-btn" @click="goMyCoupons">去查看我的优惠券</view>
</view>
</view>
</view>
</template>
<script>
import { getDrawActivityInfo, getActivityWinRecord, getDrawMyTickets } from '@/api/lottery'
export default {
data() {
return {
webUrl: this.$VUE_APP_RESOURCES_URL,
statusBarHeight: 20,
activityId: 0,
periodLabel: "01",
drawTime: "--",
hasWon: 0,
userWinList: [],
activityWinnerList: [],
loaded: false,
showCouponSuccessPopup: false
}
},
onLoad(options) {
this.activityId = Number(options && options.activityId) || 0
const systemInfo = uni.getSystemInfoSync()
this.statusBarHeight = systemInfo.statusBarHeight || 20
this.fetchData()
},
methods: {
goBack() {
uni.navigateBack()
},
navToMyTickets() {
uni.navigateTo({
url: '/pkg-video/views/county-my-tickets'
})
},
handleClaimNow() {
if (!this.userWinList.length) return
const allCouponPrize = this.userWinList.every((item) => this.isCouponPrize(item))
if (allCouponPrize) {
this.showCouponSuccessPopup = true
return
}
if (this.userWinList.length === 1) {
this.navToReceiveInfo(this.userWinList[0])
return
}
this.navToMyTickets()
},
isCouponPrize(prize = {}) {
const prizeType = Number(prize.prizeType)
const prizeName = String(prize.prizeName || "")
return prizeType === 3 || prize.prizeType === "coupon" || /券/.test(prizeName)
},
navToReceiveInfo(prize = {}) {
const query = `?source=lottery&ticketCode=${encodeURIComponent(prize.ticketCode || "")}&prizeName=${encodeURIComponent(prize.prizeName || "")}`
uni.navigateTo({
url: `/pages/user/address/AddAddress/index${query}`
})
},
closeCouponSuccessPopup() {
this.showCouponSuccessPopup = false
},
goMyCoupons() {
this.showCouponSuccessPopup = false
uni.navigateTo({
url: "/pkg_user/views/myCoupons"
})
},
normalizeListData(res) {
if (!res) return []
if (Array.isArray(res)) return res
if (Array.isArray(res.data)) return res.data
if (Array.isArray(res.data && res.data.list)) return res.data.list
if (Array.isArray(res.list)) return res.list
return []
},
formatDrawTime(time) {
if (!time) return "--"
const date = new Date(String(time).replace(/-/g, "/"))
if (Number.isNaN(date.getTime())) return String(time)
const y = date.getFullYear()
const m = String(date.getMonth() + 1).padStart(2, "0")
const d = String(date.getDate()).padStart(2, "0")
return `${y}${m}${d}日`
},
parsePeriodLabel(info = {}, winners = []) {
const periodText = String(info.periodNo || info.currentPeriodNo || info.periodLabel || "")
if (periodText) {
const match = periodText.match(/\d+/)
if (match && match[0]) return match[0].padStart(2, "0")
}
const firstWinner = winners[0] || {}
const winnerPeriod = String(firstWinner.periodNo || "")
const winnerMatch = winnerPeriod.match(/\d+/)
if (winnerMatch && winnerMatch[0]) return winnerMatch[0].padStart(2, "0")
return "01"
},
mapUserWinList(ticketList = []) {
return ticketList.map(item => ({
levelName: item.levelName || item.prizeLevelName || "中奖奖品",
prizeName: item.prizeName || item.awardName || "神秘奖品",
prizeDesc: item.prizeDesc || item.remark || "默认",
ticketCode: item.ticketCode || item.code || "--",
prizeType: item.prizeType,
prizeImage: item.prizeImage || item.image || ""
}))
},
async fetchData() {
try {
const [activityRes, winnerRes, myTicketsRes] = await Promise.all([
this.activityId ? getDrawActivityInfo(this.activityId) : Promise.resolve(null),
this.activityId ? getActivityWinRecord(this.activityId) : Promise.resolve(null),
getDrawMyTickets(1)
])
const activityData = (activityRes && activityRes.data) || {}
const winnerList = this.normalizeListData(winnerRes)
const myTicketList = this.normalizeListData(myTicketsRes)
const filteredMyTicketList = this.activityId
? myTicketList.filter(item => Number(item.activityId || item.drawActivityId || 0) === this.activityId)
: myTicketList
this.drawTime = this.formatDrawTime(activityData.drawTime || activityData.openTime || "")
this.activityWinnerList = winnerList
this.userWinList = this.mapUserWinList(filteredMyTicketList)
this.hasWon = this.userWinList.length > 0 ? 1 : 0
this.periodLabel = this.parsePeriodLabel(activityData, winnerList)
} catch (e) {
uni.showToast({
title: "中奖数据加载失败",
icon: "none"
})
} finally {
this.loaded = true
}
}
}
}
</script>
<style lang="less" scoped>
.winners-page {
min-height: 100vh;
background: #f4f6f8;
padding-bottom: 48rpx;
font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif;
}
.custom-header {
position: sticky;
top: 0;
left: 0;
right: 0;
z-index: 99;
background-color: #fff;
.header-inner {
height: 44px;
display: flex;
align-items: center;
position: relative;
padding: 0 24rpx;
.header-back {
width: 60rpx;
height: 60rpx;
display: flex;
align-items: center;
justify-content: center;
border-radius: 8rpx;
.header-back-icon {
font-size: 60rpx;
color: #333;
margin-top: -4rpx;
}
}
.header-title {
flex: 1;
text-align: center;
font-size: 34rpx;
font-weight: 700;
color: #333;
}
.header-actions {
width: 120rpx;
height: 56rpx;
border-radius: 28rpx;
display: flex;
align-items: center;
justify-content: space-around;
padding: 0 16rpx;
.dot {
font-size: 22rpx;
color: #333;
font-weight: bold;
letter-spacing: 2rpx;
}
.circle-dot {
width: 20rpx;
height: 20rpx;
border: 3rpx solid #333;
border-radius: 50%;
position: relative;
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 6rpx;
height: 6rpx;
background: #333;
border-radius: 50%;
}
}
}
}
}
.content-wrap {
padding: 28rpx 24rpx 0;
}
.draw-info-wrap {
position: relative;
margin: 18rpx 0 38rpx;
padding: 24rpx 70rpx;
display: flex;
align-items: center;
min-height: 168rpx;
background-size: 100% 100%;
background-repeat: no-repeat;
background-color: transparent;
.period-side {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 54rpx;
height: 152rpx;
border-radius: 16rpx;
display: flex;
align-items: center;
justify-content: center;
background: #fff4d1;
padding-bottom: 15rpx;
.side-text {
font-size: 24rpx;
line-height: 1.1;
font-weight: 900;
letter-spacing: 2rpx;
color: #1f1f1f;
}
.side-text-count {
writing-mode: horizontal-tb;
height: 132rpx;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
letter-spacing: 0;
line-height: 1;
}
&.left {
left: 8rpx;
background: transparent;
display: flex;
flex-direction: column;
align-items: center;
}
&.right {
right: 8rpx;
background: transparent;
}
}
.draw-main {
flex: 1;
border-radius: 16rpx;
text-align: center;
padding: 18rpx 12rpx;
}
.draw-title {
font-size: 58rpx;
line-height: 1.05;
color: #d73222;
font-weight: 900;
letter-spacing: 1rpx;
margin-bottom: 8rpx;
}
.draw-time {
font-size: 30rpx;
color: #222;
font-weight: 800;
}
}
.win-banner {
padding: 54rpx 20rpx 26rpx;
text-align: center;
margin-bottom: 62rpx;
position: relative;
background-size: 100%;
background-repeat: no-repeat;
background-color: transparent;
.win-badge {
position: absolute;
top: -34rpx;
left: 50%;
transform: translateX(-50%);
width: 390rpx;
height: 72rpx;
background: #ffca1c;
border: 4rpx solid #1f1f1f;
border-radius: 18rpx;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 5rpx 0 #d49400;
.win-badge-text {
font-size: 52rpx;
font-weight: 900;
color: #fff;
text-shadow: -2rpx -2rpx 0 #1f1f1f, 2rpx -2rpx 0 #1f1f1f, -2rpx 2rpx 0 #1f1f1f, 2rpx 2rpx 0 #1f1f1f, 0 4rpx 0 #1f1f1f;
letter-spacing: 1rpx;
}
}
.win-banner-subtitle {
font-size: 28rpx;
color: #fff;
margin-bottom: 20rpx;
margin-top: 8rpx;
font-weight: 700;
.code {
font-weight: 900;
font-size: 40rpx;
margin: 0 8rpx;
color: #ffe8db;
}
}
.prize-card {
background: #fffdf5;
border: 4rpx solid #1f1f1f;
border-radius: 20rpx;
padding: 12rpx;
display: flex;
align-items: flex-start;
margin-bottom: 18rpx;
text-align: left;
box-shadow: inset 0 0 0 2rpx #fff;
.prize-img-wrap {
width: 132rpx;
height: 132rpx;
border-radius: 12rpx;
border: 2rpx dashed #b3b3b3;
padding: 4rpx;
margin-right: 18rpx;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
.prize-img {
width: 100%;
height: 100%;
border-radius: 8rpx;
}
}
.prize-info {
flex: 1;
padding-top: 8rpx;
.prize-name-wrap {
font-size: 40rpx;
color: #222;
margin-bottom: 10rpx;
line-height: 1.2;
.prize-level {
font-weight: 900;
}
.prize-name {
font-weight: 700;
}
}
.prize-desc {
font-size: 34rpx;
color: #8c8c8c;
font-weight: 600;
}
}
}
.my-tickets-btn {
background: linear-gradient(180deg, #ffd33d 0%, #ffb300 100%);
border: 4rpx solid #1f1f1f;
border-radius: 48rpx;
padding: 0;
height: 90rpx;
width: 92%;
margin: 0 auto;
display: flex;
align-items: center;
justify-content: center;
box-shadow: inset 0 -8rpx 0 rgba(0, 0, 0, 0.12), 0 8rpx 0 #1f1f1f;
transition: all 0.1s;
&:active {
transform: translateY(4rpx);
box-shadow: inset 0 -4rpx 0 rgba(0, 0, 0, 0.12), 0 4rpx 0 #1f1f1f;
}
.btn-text {
font-size: 50rpx;
font-weight: 900;
color: #fff;
text-shadow: -2rpx -2rpx 0 #1f1f1f, 2rpx -2rpx 0 #1f1f1f, -2rpx 2rpx 0 #1f1f1f, 2rpx 2rpx 0 #1f1f1f, 0 4rpx 0 #1f1f1f;
letter-spacing: 2rpx;
}
}
.claim-tip {
margin-top: 16rpx;
color: #fff0de;
font-size: 30rpx;
font-weight: 700;
}
}
.winners-list-wrap {
background: #fff;
border-radius: 28rpx;
padding: 46rpx 24rpx 10rpx;
position: relative;
box-shadow: 0 5rpx 0 #e6e8ec;
.list-title-badge {
position: absolute;
left: 50%;
top: -30rpx;
transform: translateX(-50%);
display: flex;
align-items: center;
padding: 14rpx 34rpx;
background-size: 100% 100%;
background-repeat: no-repeat;
background-color: transparent;
.gift-icon {
font-size: 28rpx;
margin-right: 8rpx;
}
.title-text {
font-size: 34rpx;
font-weight: 900;
color: #222;
}
}
.list-content {
.list-item {
display: flex;
justify-content: space-between;
align-items: flex-start;
padding: 24rpx 0;
border-bottom: 2rpx solid #f1f1f1;
&:last-child {
border-bottom: none;
}
.item-left {
flex: 1;
.item-prize {
font-size: 36rpx;
color: #333;
margin-bottom: 8rpx;
line-height: 1.25;
.level {
font-weight: 900;
}
.name {
font-weight: 700;
}
}
.item-code {
font-size: 32rpx;
color: #666;
font-weight: 700;
.code-text {
color: #d8392b;
font-weight: 900;
}
}
}
.item-right {
margin-left: 16rpx;
text-align: right;
.user-name {
font-size: 32rpx;
color: #666;
font-weight: 700;
margin-bottom: 8rpx;
}
.user-phone {
font-size: 30rpx;
color: #999;
font-weight: 600;
}
}
}
.empty-text {
text-align: center;
padding: 60rpx 0;
color: #999;
font-size: 28rpx;
}
}
}
.coupon-popup-mask {
position: fixed;
inset: 0;
z-index: 1000;
background: rgba(0, 0, 0, 0.55);
display: flex;
align-items: center;
justify-content: center;
padding: 24rpx;
}
.coupon-popup {
width: 100%;
max-width: 620rpx;
background: #fff;
border-radius: 32rpx;
padding: 26rpx 34rpx 42rpx;
position: relative;
}
.popup-close {
position: absolute;
right: 18rpx;
top: 18rpx;
width: 40rpx;
height: 40rpx;
border-radius: 50%;
border: 2rpx solid #333;
font-size: 40rpx;
font-weight: 700;
color: #333;
line-height: 40rpx;
text-align: center;
}
.popup-icon-wrap {
width: 112rpx;
height: 112rpx;
margin: 20rpx auto 8rpx;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
}
.popup-icon {
font-size: 70rpx;
}
.popup-title {
text-align: center;
font-size: 60rpx;
font-weight: 900;
color: #222;
margin-top: 12rpx;
}
.popup-desc {
margin: 38rpx auto 42rpx;
text-align: center;
font-size: 28rpx;
line-height: 1.6;
color: #9a9a9a;
width: 92%;
}
.popup-btn {
width: 86%;
height: 96rpx;
margin: 0 auto;
border-radius: 48rpx;
background: #c43124;
color: #fff;
font-size: 40rpx;
font-weight: 900;
text-align: center;
line-height: 96rpx;
letter-spacing: 2rpx;
}
</style>