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

551 lines
12 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-my-tickets-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 class="header-right">
<view class="right-dot"></view>
<view class="right-ring"></view>
</view>
</view>
<view class="tabs">
<view
v-for="tab in tabs"
:key="tab.key"
class="tab-item"
:class="{ active: activeTab === tab.key }"
@click="onChangeTab(tab.key)"
>
{{ tab.label }}
</view>
</view>
</view>
<scroll-view class="page-body" scroll-y :style="{ paddingTop: `calc(${statusBarHeight}px + 168rpx)` }">
<view class="tip-bar" v-if="summaryText">
<view class="tip-text one-t">{{ summaryText }}</view>
<view class="tip-btn" @click="goWinnersPage">查看全部 <text class="icon-expand"></text></view>
</view>
<view class="ticket-list" v-if="displayList.length">
<view class="ticket-card" v-for="item in displayList" :key="item.id">
<view class="ticket-head">
<view class="ticket-code">
<text class="code-icon">🎟</text>
<text class="code-label">抽奖码:</text>
<text class="code-value">{{ item.ticketCode || '--' }}</text>
</view>
<view class="ticket-status" :class="[ `status-${item.status}`, item.status === 0 ? 'status-pill' : '', item.status === 1 && item.claimStatus === 1 ? 'status-claimed' : '' ]">{{ getStatusText(item) }}</view>
</view>
<view class="ticket-info-row">
<text class="label">来源订单</text>
<text class="value">{{ item.sourceOrderId || '--' }}</text>
</view>
<view class="ticket-info-row">
<text class="label">开奖时间</text>
<text class="value">{{ formatDrawTime(item.drawTime) }}</text>
</view>
<view class="prize-box" v-if="showPrize(item)">
恭喜获得{{ item.prizeName || '神秘奖品' }}
</view>
<view class="ticket-footer" v-if="item.status === 1">
<template v-if="item.claimStatus === 0">
<view class="footer-note">注意请在7天内领取过期不予发放</view>
<view class="footer-btn btn-claim" @click="onClaim(item)"> </view>
</template>
<template v-else-if="item.claimStatus === 1">
<view class="footer-note done">奖品已领取</view>
<view class="footer-btn btn-order" @click="goOrder(item)">查看订单</view>
</template>
</view>
<view class="invalid-reason" v-if="item.status === -1">
失效原因{{ getInvalidReason(item) }}
</view>
</view>
</view>
<view class="empty-wrap" v-else>
<view class="empty-text">{{ loading ? '加载中...' : '暂无抽奖码记录' }}</view>
</view>
</scroll-view>
</view>
</template>
<script>
// import { getDrawMyTickets } from '@/api/lottery'
export default {
name: 'CountyMyTicketsPage',
data() {
return {
statusBarHeight: 20,
loading: false,
activeTab: 'all',
activityId: 1,
tabs: [
{ key: 'all', label: '全部' },
{ key: 'wait', label: '待开奖' },
{ key: 'opened', label: '已开奖' },
{ key: 'invalid', label: '已失效' }
],
list: [],
openedList: []
}
},
computed: {
displayList() {
return this.activeTab === 'opened' ? this.openedList : this.list
},
summaryText() {
return `恭喜海*在第01期抽奖活动中获得 iPhone17 pro 手机`
}
},
onLoad(options) {
if (options && options.activityId) {
this.activityId = Number(options.activityId) || 1
}
},
onShow() {
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight || 20
this.fetchList()
},
methods: {
mapTabToStatus(tab) {
const map = {
wait: 0,
invalid: -1
}
return map[tab]
},
onChangeTab(tab) {
if (this.activeTab === tab) return
this.activeTab = tab
this.fetchList()
},
goWinnersPage() {
uni.navigateTo({
url: `/pkg-video/views/county-winners?activityId=${this.activityId}`
})
},
fetchList() {
this.loading = true
// 使用模拟数据以匹配设计图所有状态
setTimeout(() => {
const mockData = [
{
id: 1,
ticketCode: 'A8F92E',
status: 0,
sourceOrderId: '12345678910',
drawTime: '2026-05-30 10:00:00',
},
{
id: 2,
ticketCode: 'A8F92E',
status: 1,
claimStatus: 0,
sourceOrderId: '12345678910',
drawTime: '2026-05-30 10:00:00',
prizeName: '一等奖ipone17 pro max手机'
},
{
id: 3,
ticketCode: 'A8F92E',
status: 1,
claimStatus: 1,
sourceOrderId: '12345678910',
drawTime: '2026-05-30 10:00:00',
prizeName: '一等奖ipone17 pro max手机'
},
{
id: 4,
ticketCode: 'A8F92E',
status: -1,
claimStatus: 0,
sourceOrderId: '12345678910',
drawTime: '2026-05-30 10:00:00',
},
{
id: 5,
ticketCode: 'A8F92E',
status: -1,
claimStatus: -1,
sourceOrderId: '12345678910',
drawTime: '2026-05-30 10:00:00',
prizeName: '一等奖ipone17 pro max手机'
}
];
let filteredData = mockData;
if (this.activeTab === 'wait') {
filteredData = mockData.filter(item => item.status === 0);
} else if (this.activeTab === 'opened') {
filteredData = mockData.filter(item => item.status === 1 || item.status === 2);
} else if (this.activeTab === 'invalid') {
filteredData = mockData.filter(item => item.status === -1);
}
this.list = filteredData;
this.openedList = mockData.filter(item => item.status === 1 || item.status === 2);
this.loading = false;
}, 300);
},
getStatusText(item) {
const status = Number(item.status)
if (status === 0) return '等待开奖'
if (status === 1) return item.claimStatus === 1 ? '已领取' : '已开奖'
if (status === 2) return '已开奖'
if (status === -1) return '已失效'
return '--'
},
showPrize(item) {
return [1, 2, -1].includes(Number(item.status)) && !!item.prizeName
},
getInvalidReason(item) {
if (Number(item.claimStatus) === -1) return '奖品过期未领取'
return '订单取消'
},
formatDrawTime(time) {
if (!time) return '--'
const date = new Date(String(time).replace(/-/g, '/'))
if (Number.isNaN(date.getTime())) return time
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')
return `${y}${m}${d}${hh}:${mm}`
},
onClaim(item) {
if (!item.id) return
uni.navigateTo({
url: `/pages/order/OrderSubmission/index?lotteryRecordId=${item.id}`
})
},
goOrder(item) {
if (!item.sourceOrderId) {
uni.showToast({
title: '缺少订单号',
icon: 'none'
})
return
}
uni.navigateTo({
url: `/pages/order/OrderDetails/index?id=${item.sourceOrderId}`
})
},
goBack() {
if (getCurrentPages().length > 1) {
uni.navigateBack()
return
}
uni.switchTab({
url: '/pages/home/index'
})
}
}
}
</script>
<style scoped lang="less">
.county-my-tickets-page {
min-height: 100vh;
background: #f5f5f5;
}
.custom-header {
position: fixed;
left: 0;
top: 0;
width: 100%;
z-index: 20;
background: #f5f5f5;
}
.header-inner {
height: 88rpx;
padding: 0 24rpx;
display: flex;
align-items: center;
}
.header-back {
width: 56rpx;
height: 56rpx;
border-radius: 8rpx;
display: flex;
align-items: center;
justify-content: center;
}
.header-back-icon {
font-size: 60rpx;
color: #111;
line-height: 1;
margin-top: -4rpx;
}
.header-title {
flex: 1;
text-align: center;
margin-left: 56rpx;
font-size: 34rpx;
color: #333;
font-weight: 700;
}
.header-right {
width: 88rpx;
height: 44rpx;
border-radius: 24rpx;
border: 2rpx solid #d8d8d8;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
}
.right-dot {
width: 8rpx;
height: 8rpx;
border-radius: 50%;
background: #111;
margin-right: 14rpx;
}
.right-ring {
width: 18rpx;
height: 18rpx;
border-radius: 50%;
border: 2rpx solid #111;
}
.tabs {
height: 80rpx;
padding: 0 24rpx;
display: flex;
align-items: center;
background: #f5f5f5;
}
.tab-item {
margin-right: 20rpx;
padding: 8rpx 24rpx;
border-radius: 30rpx;
color: #666;
font-size: 26rpx;
background: #fff;
}
.tab-item.active {
color: #BD3124;
background: rgba(220,60,53,0.39);
}
.page-body {
box-sizing: border-box;
height: 100vh;
}
.tip-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 10rpx 24rpx;
font-size: 24rpx;
color: #666;
background: #fff;
border-radius: 160rpx;
margin: 0 20rpx;
}
.tip-text {
flex: 1;
font-weight: 500;
color: #333;
}
.tip-btn {
background: #FCF9EA;
padding: 6rpx 16rpx;
border-radius: 20rpx;
display: flex;
align-items: center;
font-size: 22rpx;
color: #333;
margin-left: 10rpx;
}
.icon-expand {
font-size: 20rpx;
margin-left: 4rpx;
}
.ticket-list {
padding-top: 10rpx;
padding-bottom: 40rpx;
}
.ticket-card {
background: #fff;
border-radius: 16rpx;
margin: 0 24rpx 20rpx;
padding: 24rpx;
}
.ticket-head {
display: flex;
align-items: center;
justify-content: space-between;
padding-bottom: 20rpx;
border-bottom: 2rpx dashed #eee;
margin-bottom: 20rpx;
position: relative;
}
.ticket-code {
display: flex;
align-items: center;
color: #333;
}
.code-icon {
margin-right: 8rpx;
color: #333;
font-size: 28rpx;
}
.code-label {
font-size: 32rpx;
font-weight: 700;
margin-right: 12rpx;
}
.code-value {
font-size: 34rpx;
font-weight: 700;
letter-spacing: 1rpx;
}
.ticket-status {
font-size: 26rpx;
font-weight: bold;
}
.status-pill {
background: #BD3124;
color: #fff;
padding: 4rpx 16rpx;
border-radius: 20rpx 0 0 20rpx;
font-size: 24rpx;
font-weight: normal;
position: absolute;
right: -24rpx;
}
.status-0 {
/* handled by pill */
}
.status-1,
.status-2 {
color: #BD3124;
}
.status-claimed {
color: #999 !important;
}
.status--1 {
color: #999;
}
.ticket-info-row {
margin-top: 14rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.ticket-info-row .label {
color: #999;
font-size: 26rpx;
}
.ticket-info-row .value {
color: #333;
font-size: 26rpx;
}
.prize-box {
margin-top: 24rpx;
border: 2rpx solid #BD3124;
border-radius: 40rpx;
color: #BD3124;
font-size: 30rpx;
text-align: center;
padding: 16rpx 0;
font-weight: 600;
}
.ticket-footer {
margin-top: 20rpx;
display: flex;
align-items: center;
justify-content: space-between;
}
.footer-note {
flex: 1;
color: #BD3124;
font-size: 22rpx;
}
.footer-note.done {
color: #BD3124;
}
.footer-btn {
width: 170rpx;
height: 54rpx;
border-radius: 30rpx;
color: #fff;
font-size: 26rpx;
display: flex;
align-items: center;
justify-content: center;
}
.btn-claim {
background: #BD3124;
}
.btn-order {
background: #BD3124;
}
.invalid-reason {
margin-top: 14rpx;
font-size: 24rpx;
color: #BD3124;
}
.empty-wrap {
padding-top: 120rpx;
text-align: center;
}
.empty-text {
color: #999;
font-size: 28rpx;
}
</style>