Files
martial-mini/pages/my-registration/my-registration.vue
2025-12-26 10:20:46 +08:00

451 lines
11 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="my-registration-page">
<!-- Tab切换 -->
<custom-tabs :tabs="tabs" :current="currentTab" @change="handleTabChange"></custom-tabs>
<!-- 赛事列表 -->
<view class="event-list">
<view
class="event-item"
v-for="(item, index) in filteredList"
:key="index"
@click="goToEventDetail(item)"
>
<view class="status-tag" :class="getStatusClass(item.status)">
<text>{{ getStatusText(item.status) }}</text>
</view>
<view class="event-title">{{ item.title }}</view>
<view class="event-info">
<text class="label">地点</text>
<text class="value">{{ item.location }}</text>
</view>
<view class="event-info">
<text class="label">比赛时间</text>
<text class="value">{{ item.matchTime }}</text>
</view>
<view class="event-info">
<text class="label">报名项目</text>
<text class="value">{{ item.projects }}</text>
</view>
<view class="event-info">
<text class="label">联系人</text>
<text class="value">{{ item.contact }}</text>
</view>
<view class="event-info">
<text class="label">参赛选手</text>
<text class="value participants">{{ item.participants }}</text>
</view>
<view class="event-footer" v-if="item.status === 'ongoing'">
<view class="register-note">
<text>点击后进入赛事详情页面</text>
</view>
<view class="view-cert-btn" @click.stop="handleViewCert(item)">
<text>查看证件</text>
<text class="arrow"></text>
</view>
</view>
</view>
</view>
<!-- 空状态 -->
<view class="empty-state" v-if="filteredList.length === 0">
<text class="empty-text">暂无报名记录</text>
</view>
</view>
</template>
<script>
import CustomTabs from '../../components/custom-tabs/custom-tabs.vue';
import registrationAPI from '@/api/registration.js'
import competitionAPI from '@/api/competition.js'
import { getUserInfo } from '@/utils/auth.js'
export default {
components: {
CustomTabs
},
data() {
return {
tabs: ['全部', '待开始', '进行中', '已结束'],
currentTab: 0,
eventList: [],
// 分页参数
pageParams: {
current: 1,
size: 20
},
hasMore: true
};
},
onLoad() {
this.loadRegistrationList()
},
// 下拉刷新
onPullDownRefresh() {
this.pageParams.current = 1
this.loadRegistrationList(true)
},
// 上拉加载更多
onReachBottom() {
if (this.hasMore) {
this.pageParams.current++
this.loadRegistrationList(false, true)
}
},
computed: {
filteredList() {
if (this.currentTab === 0) {
return this.eventList;
}
const statusMap = {
1: 'pending',
2: 'ongoing',
3: 'finished'
};
return this.eventList.filter(item => item.status === statusMap[this.currentTab]);
}
},
methods: {
/**
* 加载我的报名列表
* @param {Boolean} refresh 是否刷新(重置列表)
* @param {Boolean} loadMore 是否加载更多(追加列表)
*/
async loadRegistrationList(refresh = false, loadMore = false) {
try {
// 获取当前用户信息
const userInfo = getUserInfo()
console.log('=== 用户信息调试 ===')
console.log('获取到的用户信息:', userInfo)
console.log('用户信息类型:', typeof userInfo)
if (!userInfo || (!userInfo.userId && !userInfo.user_id)) {
console.error('未获取到用户信息或缺少用户ID字段')
console.log('原始存储数据:', uni.getStorageSync('userInfo'))
uni.showToast({
title: '请先登录',
icon: 'none'
})
return
}
// 兼容 userId 和 user_id 两种字段名
const userId = userInfo.userId || userInfo.user_id
const params = {
current: this.pageParams.current,
size: this.pageParams.size,
createUser: userId // 只查询当前用户创建的报名记录
}
// 添加状态筛选
if (this.currentTab > 0) {
params.status = this.currentTab
}
const res = await registrationAPI.getRegistrationList(params)
console.log('=== 我的报名列表 - 后端返回的原始数据 ===')
console.log('完整响应:', res)
let list = []
let total = 0
// 处理分页数据
if (res.records) {
list = res.records
total = res.total || 0
} else if (Array.isArray(res)) {
list = res
total = res.length
}
// 为每条报名记录获取详情(包含关联数据)
const detailPromises = list.map(item => this.getRegistrationDetailData(item))
const mappedList = await Promise.all(detailPromises)
// 过滤掉获取失败的记录
const validList = mappedList.filter(item => item !== null)
// 刷新或加载更多
if (refresh || !loadMore) {
this.eventList = validList
} else {
this.eventList = [...this.eventList, ...validList]
}
// 判断是否还有更多数据
this.hasMore = this.eventList.length < total
// 停止下拉刷新
if (refresh) {
uni.stopPullDownRefresh()
}
} catch (err) {
console.error('加载报名列表失败:', err)
uni.stopPullDownRefresh()
}
},
/**
* 获取单条报名记录的详细信息
* @param {Object} orderItem 订单基本信息
* @returns {Promise<Object>} 包含完整信息的记录
*/
async getRegistrationDetailData(orderItem) {
try {
console.log('=== 获取报名详情 ===', orderItem.id)
// 获取报名详情
const detail = await registrationAPI.getRegistrationDetail(orderItem.id)
console.log('报名详情:', detail)
// 获取赛事详情
let competitionInfo = null
if (orderItem.competitionId || detail.competitionId) {
const competitionId = orderItem.competitionId || detail.competitionId
competitionInfo = await competitionAPI.getCompetitionDetail(competitionId)
console.log('赛事详情:', competitionInfo)
}
// 构建映射数据
const mapped = {
id: orderItem.id,
status: this.getStatus(orderItem.status),
title: competitionInfo?.name || detail.competitionName || '未知赛事',
location: competitionInfo?.location || competitionInfo?.address || detail.location || '',
matchTime: this.formatTimeRange(
competitionInfo?.startTime || detail.startTime,
competitionInfo?.endTime || detail.endTime
) || '',
projects: detail.projectNames || this.formatProjects(detail.projects || detail.projectList) || '',
contact: orderItem.contactPhone || detail.contactPhone || '',
participants: detail.athleteNames || this.formatParticipants(detail.athletes || detail.athleteList) || ''
}
console.log('映射后的数据:', mapped)
return mapped
} catch (err) {
console.error('获取报名详情失败:', err, orderItem.id)
// 返回基本信息,避免整个记录丢失
return {
id: orderItem.id,
status: this.getStatus(orderItem.status),
title: '获取详情失败',
location: '',
matchTime: '',
projects: '',
contact: orderItem.contactPhone || '',
participants: `${orderItem.registerCount || 0}`
}
}
},
/**
* 格式化时间范围
*/
formatTimeRange(startTime, endTime) {
if (!startTime || !endTime) return ''
const formatDate = (dateStr) => {
if (!dateStr) return ''
const date = new Date(dateStr)
const year = date.getFullYear()
const month = String(date.getMonth() + 1).padStart(2, '0')
const day = String(date.getDate()).padStart(2, '0')
return `${year}.${month}.${day}`
}
return `${formatDate(startTime)}-${formatDate(endTime)}`
},
/**
* 获取报名状态
*/
getStatus(status) {
// 1: 待开始, 2: 进行中, 3: 已结束
const statusMap = {
1: 'pending',
2: 'ongoing',
3: 'finished',
'pending': 'pending',
'ongoing': 'ongoing',
'finished': 'finished'
}
return statusMap[status] || 'pending'
},
/**
* 格式化报名项目
*/
formatProjects(projects) {
if (!projects) return ''
if (Array.isArray(projects)) {
return projects.map(p => p.name || p.projectName).join('、')
}
return projects
},
/**
* 格式化参赛选手
*/
formatParticipants(athletes) {
if (!athletes) return ''
if (Array.isArray(athletes)) {
return athletes.map(a => a.name || a.athleteName).join('、')
}
return athletes
},
handleTabChange(index) {
this.currentTab = index;
// 切换tab时重新加载
this.pageParams.current = 1
this.loadRegistrationList(true)
},
getStatusClass(status) {
return {
'status-ongoing': status === 'ongoing',
'status-pending': status === 'pending',
'status-finished': status === 'finished'
};
},
getStatusText(status) {
const statusMap = {
ongoing: '进行中',
pending: '待开始',
finished: '已结束'
};
return statusMap[status] || '';
},
goToEventDetail(item) {
uni.navigateTo({
url: '/pages/event-detail/event-detail?id=' + item.id
});
},
handleViewCert(item) {
uni.showToast({
title: '查看证件',
icon: 'none'
});
}
}
};
</script>
<style lang="scss" scoped>
.my-registration-page {
min-height: 100vh;
background-color: #f5f5f5;
}
.event-list {
padding: 30rpx;
}
.event-item {
background-color: #fff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 20rpx;
position: relative;
}
.status-tag {
position: absolute;
top: 30rpx;
left: 30rpx;
padding: 8rpx 20rpx;
border-radius: 8rpx;
font-size: 24rpx;
color: #fff;
}
.status-ongoing {
background-color: #4CAF50;
}
.status-pending {
background-color: #FF9800;
}
.status-finished {
background-color: #999999;
}
.event-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
margin: 50rpx 0 20rpx;
line-height: 1.5;
}
.event-info {
display: flex;
margin-bottom: 10rpx;
}
.label {
font-size: 26rpx;
color: #666666;
flex-shrink: 0;
}
.value {
font-size: 26rpx;
color: #666666;
flex: 1;
}
.participants {
word-break: break-all;
}
.event-footer {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 20rpx;
padding-top: 20rpx;
border-top: 1rpx solid #f5f5f5;
}
.register-note {
font-size: 24rpx;
color: #C93639;
}
.view-cert-btn {
display: flex;
align-items: center;
padding: 10rpx 20rpx;
border: 2rpx solid #C93639;
border-radius: 8rpx;
font-size: 24rpx;
color: #C93639;
}
.arrow {
font-size: 28rpx;
margin-left: 5rpx;
}
.empty-state {
padding: 200rpx 0;
text-align: center;
}
.empty-text {
font-size: 28rpx;
color: #999999;
}
</style>