Compare commits

..
8 Commits
Author SHA1 Message Date
DevOps 56a1897b7d fix: 修复选手列表重复问题 - 只查询registrationStatus=0的选手信息记录
根本原因:报名时会创建新的registrationStatus=1参赛记录,而查询选手列表时没有过滤,导致显示重复
解决方案:在查询选手列表时添加registrationStatus=0参数,只查询选手信息库
2026-01-15 17:20:02 +08:00
DevOps 5f68218079 fix: 修复选手/集体列表重复问题,添加集体项目已报名标记
- add-team.vue: 添加选手列表去重逻辑
- event-register.vue: loadTeamList添加去重和已报名标记
- event-register.vue: toggleTeam添加已报名警告
- 集体项目UI显示已报名标签
2026-01-15 16:52:08 +08:00
DevOps 82deb8b4f9 fix: 选手列表去重并显示已报名标记
- loadPlayerList 添加按身份证去重逻辑
- 查询已报名选手并标记 hasRegistered
- UI 显示"已报名"标签
- 选择已报名选手时弹出警告

Closes #3, Closes #4
2026-01-15 15:57:08 +08:00
DevOpsandfactory-droid[bot] 076aa287bd fix: 报名时强制验证联系人是否已选择
- 在goToStep3方法中添加selectedContact验证
- 未选择联系人时显示提示并阻止提交
- 修复Issue #2

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-01-15 15:57:08 +08:00
DevOpsandfactory-droid[bot] d8c255d69d 出场顺序:显示预计出场时间和状态样式
- 显示预计出场时间(单位 | 时间)
- 状态样式:已完成(绿色)、进行中(橙色)、待出场(灰色)

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-01-15 15:57:08 +08:00
Z-WICK 7c4507c3ed sync changes: 出场顺序优化、联系人功能 2026-01-15 15:57:08 +08:00
DevOpsandfactory-droid[bot] 412069524e fix: 新增联系人后刷新列表
- 问题2: 在onShow生命周期中自动刷新联系人列表

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-01-08 16:08:39 +08:00
DevOpsandfactory-droid[bot] 53cc4600a8 重构项4: 小程序出场顺序页面改用真实数据
- 修改api/schedule.js添加getScheduleStatus和getLineup方法
- 重写event-lineup.vue,从硬编码mock数据改为调用后端API
- 添加编排未完成状态的友好提示

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
2026-01-08 15:42:55 +08:00
9 changed files with 420 additions and 147 deletions
+7
View File
@@ -81,5 +81,12 @@ export default {
removeContact(id) { removeContact(id) {
return request.post('/martial/contact/remove?ids=' + id, {}) return request.post('/martial/contact/remove?ids=' + id, {})
},
/**
* 获取已报名选手列表(用于检查重复报名)
*/
getRegisteredAthletes(params = {}) {
return request.get('/martial/athlete/registered', params)
} }
} }
+25 -2
View File
@@ -10,7 +10,7 @@ import request from '@/utils/request.js'
*/ */
export function getScheduleResult(competitionId) { export function getScheduleResult(competitionId) {
return request.get('/martial/schedule/result', { return request.get('/martial/schedule/result', {
params: { competitionId } competitionId
}) })
} }
@@ -91,6 +91,27 @@ export function saveDispatch(data) {
return request.post('/martial/schedule/save-dispatch', data) return request.post('/martial/schedule/save-dispatch', data)
} }
/**
* 获取编排状态(小程序用)
* @param {Number} competitionId - 赛事ID
*/
export function getScheduleStatus(competitionId) {
return request.get('/mini/schedule/status', {
competitionId
})
}
/**
* 获取出场顺序(小程序用)
* @param {Number} competitionId - 赛事ID
* @param {Number} projectId - 项目ID (可选)
*/
export function getLineup(competitionId, projectId, orderId) {
return request.get('/mini/schedule/lineup', {
competitionId, projectId, orderId
})
}
export default { export default {
getScheduleResult, getScheduleResult,
triggerAutoArrange, triggerAutoArrange,
@@ -99,5 +120,7 @@ export default {
moveScheduleGroup, moveScheduleGroup,
getDispatchData, getDispatchData,
adjustOrder, adjustOrder,
saveDispatch saveDispatch,
getScheduleStatus,
getLineup
} }
+30
View File
@@ -124,6 +124,36 @@ export default {
try { try {
await athleteAPI.saveContact(this.formData); await athleteAPI.saveContact(this.formData);
uni.showToast({ title: '保存成功', icon: 'success' }); uni.showToast({ title: '保存成功', icon: 'success' });
// Set flag to notify previous page
uni.setStorageSync('contactListNeedRefresh', true);
// Notify previous page to refresh contact list
try {
const pages = getCurrentPages();
console.log('页面栈长度:', pages.length);
console.log('页面栈:', pages);
if (pages.length >= 2) {
const prevPage = pages[pages.length - 2];
console.log('上一页:', prevPage);
// Try different ways to access the component
const vm = prevPage.$vm || prevPage;
console.log('vm:', vm);
if (vm && typeof vm.loadContactList === 'function') {
console.log('调用 loadContactList');
vm.loadContactList();
} else if (vm && vm.$refs && vm.$refs.page && typeof vm.$refs.page.loadContactList === 'function') {
console.log('通过 $refs 调用');
vm.$refs.page.loadContactList();
}
}
} catch (e) {
console.error('通知上一页失败:', e);
}
// Also emit event as backup
uni.$emit('contactAdded');
setTimeout(() => { uni.navigateBack(); }, 1500); setTimeout(() => { uni.navigateBack(); }, 1500);
} catch (err) { } catch (err) {
console.error('保存联系人失败:', err); console.error('保存联系人失败:', err);
+11 -1
View File
@@ -109,7 +109,8 @@ export default {
const res = await athleteAPI.getAthleteList({ const res = await athleteAPI.getAthleteList({
current: 1, current: 1,
size: 100, size: 100,
createUser: userInfo.userId createUser: userInfo.userId,
registrationStatus: 0 // Only query player info records
}) })
let list = [] let list = []
@@ -119,6 +120,15 @@ export default {
list = res list = res
} }
// Deduplicate by id
const seen = new Set()
list = list.filter(item => {
const key = item.id
if (seen.has(key)) return false
seen.add(key)
return true
})
this.playerList = list.map(item => ({ this.playerList = list.map(item => ({
id: item.id, id: item.id,
name: item.name || item.playerName name: item.name || item.playerName
+9 -1
View File
@@ -168,7 +168,15 @@ export default {
}) })
let list = res.records || (Array.isArray(res) ? res : []) let list = res.records || (Array.isArray(res) ? res : [])
this.playerList = list.map(item => ({ // Deduplicate by idCard
const seen = new Set()
const uniqueList = list.filter(item => {
const idCard = item.idCard || item.idCardNumber
if (idCard && seen.has(idCard)) return false
if (idCard) seen.add(idCard)
return true
})
this.playerList = uniqueList.map(item => ({
id: item.id, id: item.id,
name: item.name || item.playerName, name: item.name || item.playerName,
idCard: item.idCard || item.idCardNumber, idCard: item.idCard || item.idCardNumber,
+3 -1
View File
@@ -82,6 +82,7 @@ export default {
data() { data() {
return { return {
eventId: '', eventId: '',
orderId: '',
eventInfo: { eventInfo: {
id: '', id: '',
title: '', title: '',
@@ -96,6 +97,7 @@ export default {
onLoad(options) { onLoad(options) {
if (options.id) { if (options.id) {
this.eventId = options.id this.eventId = options.id
this.orderId = options.orderId || null
this.loadEventDetail(options.id) this.loadEventDetail(options.id)
} }
}, },
@@ -192,7 +194,7 @@ export default {
if (url) { if (url) {
// 跳转时传递赛事ID // 跳转时传递赛事ID
uni.navigateTo({ uni.navigateTo({
url: `${url}?eventId=${this.eventId}` url: `${url}?eventId=${this.eventId}&orderId=${this.orderId || ""}`
}) })
} else { } else {
uni.showToast({ uni.showToast({
+175 -122
View File
@@ -1,135 +1,135 @@
<template> <template>
<view class="event-lineup-page"> <view class="event-lineup-page">
<!-- 组别选择 --> <view v-if="loading" class="loading-container">
<view class="group-tabs"> <text>加载中...</text>
<view
class="group-tab"
v-for="(group, index) in groups"
:key="index"
:class="{ active: currentGroup === index }"
@click="currentGroup = index"
>
{{ group }}
</view>
</view> </view>
<!-- 出场顺序列表 --> <view v-else-if="!isScheduleCompleted" class="not-ready">
<view class="lineup-list"> <view class="not-ready-icon">📋</view>
<view class="lineup-item" v-for="(item, index) in currentLineup" :key="index"> <text class="not-ready-text">赛程编排尚未完成</text>
<view class="lineup-order"> <text class="not-ready-hint">请等待赛事组织方完成编排后查看</text>
<view class="order-number">{{ item.order }}</view> </view>
<text class="order-text"></text>
</view> <template v-else>
<view class="lineup-info"> <!-- 组别选择 -->
<view class="lineup-name">{{ item.name }}</view> <view class="group-tabs">
<view class="lineup-detail"> <view
<text class="detail-item">{{ item.team }}</text> class="group-tab"
<text class="divider">|</text> v-for="(group, index) in groups"
<text class="detail-item">{{ item.time }}</text> :key="index"
</view> :class="{ active: currentGroupIndex === index }"
</view> @click="currentGroupIndex = index"
<view class="lineup-status" :class="item.status"> >
{{ item.statusText }} {{ group.groupName }}
</view> </view>
</view> </view>
</view>
<!-- 出场顺序列表 -->
<view class="lineup-list" v-if="currentGroup">
<view class="group-header">
<text class="group-venue">{{ currentGroup.venueName }}</text>
<text class="group-time">{{ currentGroup.timeSlot }}</text>
<text class="group-table">表号: {{ currentGroup.tableNo }}</text>
</view>
<view class="lineup-item" v-for="(item, index) in currentGroup.participants" :key="index">
<view class="lineup-order">
<view class="order-number">{{ item.order }}</view>
<text class="order-text"></text>
</view>
<view class="lineup-info">
<view class="lineup-name">{{ item.playerName }}</view>
<view class="lineup-detail">
<text class="detail-item">{{ item.organization }}</text>
<text class="detail-divider" v-if="item.estimatedTime"> | </text>
<text class="detail-item" v-if="item.estimatedTime">{{ item.estimatedTime }}</text>
</view>
</view>
<view class="lineup-status" :class="item.status">
{{ getStatusText(item.status) }}
</view>
</view>
<view v-if="!currentGroup.participants || currentGroup.participants.length === 0" class="empty-list">
<text>暂无参赛者信息</text>
</view>
</view>
</template>
</view> </view>
</template> </template>
<script> <script>
import { getScheduleStatus, getLineup } from '@/api/schedule.js'
export default { export default {
data() { data() {
return { return {
currentGroup: 0, eventId: '',
groups: ['男子A组', '男子B组', '女子A组'], orderId: '',
lineups: { loading: true,
0: [ isScheduleCompleted: false,
{ currentGroupIndex: 0,
order: 1, groups: []
name: '张三', }
team: '北京队',
time: '09:00',
status: 'finished',
statusText: '已完成'
},
{
order: 2,
name: '李四',
team: '上海队',
time: '09:15',
status: 'finished',
statusText: '已完成'
},
{
order: 3,
name: '王五',
team: '广东队',
time: '09:30',
status: 'ongoing',
statusText: '进行中'
},
{
order: 4,
name: '赵六',
team: '天津队',
time: '09:45',
status: 'waiting',
statusText: '待出场'
},
{
order: 5,
name: '刘七',
team: '江苏队',
time: '10:00',
status: 'waiting',
statusText: '待出场'
}
],
1: [
{
order: 1,
name: '孙八',
team: '浙江队',
time: '10:30',
status: 'waiting',
statusText: '待出场'
},
{
order: 2,
name: '周九',
team: '湖北队',
time: '10:45',
status: 'waiting',
statusText: '待出场'
}
],
2: [
{
order: 1,
name: '小红',
team: '四川队',
time: '14:00',
status: 'waiting',
statusText: '待出场'
},
{
order: 2,
name: '小芳',
team: '河南队',
time: '14:15',
status: 'waiting',
statusText: '待出场'
}
]
}
};
}, },
computed: { computed: {
currentLineup() { currentGroup() {
return this.lineups[this.currentGroup] || []; return this.groups[this.currentGroupIndex] || null
}
},
onLoad(options) {
if (options.eventId) {
this.eventId = options.eventId
this.orderId = options.orderId || null
this.checkScheduleStatus()
}
},
methods: {
async checkScheduleStatus() {
try {
const res = await getScheduleStatus(this.eventId)
if (res) {
this.isScheduleCompleted = res.isCompleted
if (this.isScheduleCompleted) {
await this.loadLineup()
}
}
} catch (error) {
console.error('检查编排状态失败:', error)
uni.showToast({ title: '加载失败', icon: 'none' })
} finally {
this.loading = false
}
},
async loadLineup() {
try {
const res = await getLineup(this.eventId, null, this.orderId)
if (res && res.groups) {
this.groups = res.groups
}
} catch (error) {
console.error('加载出场顺序失败:', error)
}
},
getStatusText(status) {
const map = {
'waiting': '待出场',
'未签到': '待出场',
'已完成': '已完成',
'进行中': '进行中',
'异常': '异常',
'ongoing': '进行中',
'finished': '已完成'
}
return map[status] || '待出场'
} }
} }
}; }
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -138,6 +138,38 @@ export default {
background-color: #f5f5f5; background-color: #f5f5f5;
} }
.loading-container {
display: flex;
justify-content: center;
align-items: center;
height: 300rpx;
color: #666;
}
.not-ready {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 100rpx 40rpx;
}
.not-ready-icon {
font-size: 80rpx;
margin-bottom: 30rpx;
}
.not-ready-text {
font-size: 32rpx;
color: #333;
margin-bottom: 15rpx;
}
.not-ready-hint {
font-size: 26rpx;
color: #999;
}
.group-tabs { .group-tabs {
background-color: #fff; background-color: #fff;
display: flex; display: flex;
@@ -166,6 +198,21 @@ export default {
padding: 0 30rpx 20rpx; padding: 0 30rpx 20rpx;
} }
.group-header {
background-color: #fff;
border-radius: 16rpx;
padding: 20rpx 30rpx;
margin-bottom: 20rpx;
display: flex;
justify-content: space-between;
align-items: center;
}
.group-venue, .group-time, .group-table {
font-size: 26rpx;
color: #666;
}
.lineup-item { .lineup-item {
background-color: #fff; background-color: #fff;
border-radius: 16rpx; border-radius: 16rpx;
@@ -216,10 +263,6 @@ export default {
color: #666666; color: #666666;
} }
.divider {
margin: 0 10rpx;
}
.lineup-status { .lineup-status {
padding: 8rpx 20rpx; padding: 8rpx 20rpx;
border-radius: 8rpx; border-radius: 8rpx;
@@ -227,18 +270,28 @@ export default {
flex-shrink: 0; flex-shrink: 0;
} }
.lineup-status.finished { .lineup-status.finished,
.lineup-status.已完成 {
background-color: #E8F5E9; background-color: #E8F5E9;
color: #4CAF50; color: #4CAF50;
} }
.lineup-status.ongoing { .lineup-status.ongoing,
.lineup-status.进行中 {
background-color: #FFF3E0; background-color: #FFF3E0;
color: #FF9800; color: #FF9800;
} }
.lineup-status.waiting { .lineup-status.waiting,
.lineup-status.未签到 {
background-color: #F5F5F5; background-color: #F5F5F5;
color: #999999; color: #999999;
} }
.empty-list {
text-align: center;
padding: 60rpx;
color: #999;
font-size: 28rpx;
}
</style> </style>
+159 -19
View File
@@ -30,13 +30,16 @@
</view> </view>
<view class="player-list"> <view class="player-list">
<view class="player-item" v-for="(item, index) in playerList" :key="index"> <view class="player-item" v-for="(item, index) in playerList" :key="index" :class="{ 'registered': item.hasRegistered }">
<view class="player-checkbox" @click="togglePlayer(item)"> <view class="player-checkbox" @click="togglePlayer(item)">
<image v-if="item.selected" class="checkbox-img" src="/static/images/选中@3x.png" mode="aspectFit"></image> <image v-if="item.selected" class="checkbox-img" src="/static/images/选中@3x.png" mode="aspectFit"></image>
<image v-else class="checkbox-img" src="/static/images/未选中@3x.png" mode="aspectFit"></image> <image v-else class="checkbox-img" src="/static/images/未选中@3x.png" mode="aspectFit"></image>
</view> </view>
<view class="player-info"> <view class="player-info">
<view class="player-name">{{ item.name }}</view> <view class="player-name">
{{ item.name }}
<text v-if="item.hasRegistered" class="registered-tag">已报名</text>
</view>
<view class="player-id">身份证{{ item.idCard }}</view> <view class="player-id">身份证{{ item.idCard }}</view>
</view> </view>
<view class="player-actions"> <view class="player-actions">
@@ -63,13 +66,16 @@
</view> </view>
<view class="player-list"> <view class="player-list">
<view class="player-item" v-for="(item, index) in teamList" :key="index"> <view class="player-item" v-for="(item, index) in teamList" :key="index" :class="{ 'registered': item.hasRegistered }">
<view class="player-checkbox" @click="toggleTeam(item)"> <view class="player-checkbox" @click="toggleTeam(item)">
<image v-if="item.selected" class="checkbox-img" src="/static/images/选中@3x.png" mode="aspectFit"></image> <image v-if="item.selected" class="checkbox-img" src="/static/images/选中@3x.png" mode="aspectFit"></image>
<image v-else class="checkbox-img" src="/static/images/未选中@3x.png" mode="aspectFit"></image> <image v-else class="checkbox-img" src="/static/images/未选中@3x.png" mode="aspectFit"></image>
</view> </view>
<view class="player-info"> <view class="player-info">
<view class="player-name">{{ item.name }}</view> <view class="player-name">
{{ item.name }}
<text v-if="item.hasRegistered" class="registered-tag">已报名</text>
</view>
<view class="player-id">成员数{{ item.memberCount || 0 }}</view> <view class="player-id">成员数{{ item.memberCount || 0 }}</view>
</view> </view>
<view class="player-actions"> <view class="player-actions">
@@ -282,6 +288,11 @@ export default {
} }
}, },
onLoad(options) { onLoad(options) {
// Listen for contact added event
uni.$on('contactAdded', () => {
console.log('=== 收到 contactAdded 事件 ===')
this.loadContactList()
})
if (options.eventId) { if (options.eventId) {
this.eventId = options.eventId this.eventId = options.eventId
this.loadEventDetail(options.eventId) this.loadEventDetail(options.eventId)
@@ -309,7 +320,21 @@ export default {
this.loadPlayerList() this.loadPlayerList()
} }
}, },
onUnload() {
uni.$off('contactAdded')
},
onShow() { onShow() {
console.log('=== onShow 被触发 ===')
// Check if contact list needs refresh
const needRefresh = uni.getStorageSync('contactListNeedRefresh')
if (needRefresh) {
console.log('检测到需要刷新联系人列表')
uni.removeStorageSync('contactListNeedRefresh')
this.loadContactList()
} else {
// Always refresh contact list when page shows
this.loadContactList()
}
if (this.currentStep === 1) { if (this.currentStep === 1) {
if (this.isTeamProject) { if (this.isTeamProject) {
this.loadTeamList() this.loadTeamList()
@@ -322,13 +347,19 @@ export default {
// Contact methods // Contact methods
async loadContactList() { async loadContactList() {
try { try {
console.log('=== 开始加载联系人列表 ===')
const res = await athleteAPI.getContactList({ current: 1, size: 100 }) const res = await athleteAPI.getContactList({ current: 1, size: 100 })
this.contactList = (res.records || []).map(item => ({ console.log('联系人API返回:', res)
const records = res.records || res.data?.records || []
console.log('联系人记录:', records)
this.contactList = records.map(item => ({
id: item.id, id: item.id,
name: item.name, name: item.name,
phone: item.phone, phone: item.phone,
idCard: item.idCard idCard: item.idCard,
isDefault: item.isDefault
})) }))
console.log('处理后的联系人列表:', this.contactList)
// Auto select default contact if exists // Auto select default contact if exists
if (!this.selectedContact && this.contactList.length > 0) { if (!this.selectedContact && this.contactList.length > 0) {
const defaultContact = this.contactList.find(c => c.isDefault) || this.contactList[0] const defaultContact = this.contactList.find(c => c.isDefault) || this.contactList[0]
@@ -397,16 +428,48 @@ export default {
const res = await athleteAPI.getAthleteList({ const res = await athleteAPI.getAthleteList({
current: 1, current: 1,
size: 100, size: 100,
createUser: userInfo.userId createUser: userInfo.userId,
registrationStatus: 0 // Only query player info records, not registration records
}) })
let list = res.records || (Array.isArray(res) ? res : []) let list = res.records || (Array.isArray(res) ? res : [])
this.playerList = list.map(item => ({
id: item.id, // Deduplicate by idCard
name: item.name || item.athleteName || item.playerName || '未命名', const seen = new Set()
idCard: item.idCard || item.idCardNumber || '', list = list.filter(item => {
selected: false const key = item.idCard || item.idCardNumber || item.id
})) if (seen.has(key)) return false
seen.add(key)
return true
})
// Get current project IDs
const projectIds = this.selectedProjects.map(p => p.id)
// Check which players have already registered for these projects
let registeredIdCards = []
if (projectIds.length > 0 && this.eventId) {
try {
const regRes = await athleteAPI.getRegisteredAthletes({
competitionId: this.eventId,
projectIds: projectIds.join(',')
})
registeredIdCards = (regRes || []).map(r => r.idCard)
} catch (e) {
console.log('查询已报名选手失败:', e)
}
}
this.playerList = list.map(item => {
const idCard = item.idCard || item.idCardNumber || ''
return {
id: item.id,
name: item.name || item.athleteName || item.playerName || '未命名',
idCard: idCard,
selected: false,
hasRegistered: registeredIdCards.includes(idCard)
}
})
} catch (err) { } catch (err) {
console.error('加载选手列表失败:', err) console.error('加载选手列表失败:', err)
} }
@@ -423,12 +486,43 @@ export default {
}) })
let list = res.records || (Array.isArray(res) ? res : []) let list = res.records || (Array.isArray(res) ? res : [])
this.teamList = list.map(item => ({
id: item.id, // Deduplicate by id
name: item.teamName || item.name, const seen = new Set()
memberCount: item.memberCount || 0, list = list.filter(item => {
selected: false const key = item.id
})) if (seen.has(key)) return false
seen.add(key)
return true
})
// Get current project IDs
const projectIds = this.selectedProjects.map(p => p.id)
// Check which teams have already registered for these projects
let registeredTeamNames = []
if (projectIds.length > 0 && this.eventId) {
try {
const regRes = await athleteAPI.getRegisteredAthletes({
competitionId: this.eventId,
projectIds: projectIds.join(',')
})
registeredTeamNames = (regRes || []).filter(r => r.teamName).map(r => r.teamName)
} catch (e) {
console.log('查询已报名集体失败:', e)
}
}
this.teamList = list.map(item => {
const teamName = item.teamName || item.name
return {
id: item.id,
name: teamName,
memberCount: item.memberCount || 0,
selected: false,
hasRegistered: registeredTeamNames.includes(teamName)
}
})
} catch (err) { } catch (err) {
console.error('加载集体列表失败:', err) console.error('加载集体列表失败:', err)
this.teamList = [] this.teamList = []
@@ -453,6 +547,17 @@ export default {
}, },
togglePlayer(item) { togglePlayer(item) {
// Warn if player has already registered for this project
if (item.hasRegistered && !item.selected) {
uni.showModal({
title: '提示',
content: '该选手已报名此项目,重复报名将被系统拒绝',
confirmText: '知道了',
showCancel: false
})
return
}
const index = this.playerList.findIndex(p => p.id === item.id) const index = this.playerList.findIndex(p => p.id === item.id)
if (index !== -1) { if (index !== -1) {
this.$set(this.playerList[index], 'selected', !this.playerList[index].selected) this.$set(this.playerList[index], 'selected', !this.playerList[index].selected)
@@ -460,6 +565,17 @@ export default {
}, },
toggleTeam(item) { toggleTeam(item) {
// Warn if team has already registered for this project
if (item.hasRegistered && !item.selected) {
uni.showModal({
title: '提示',
content: '该集体已报名此项目,重复报名将被系统拒绝',
confirmText: '知道了',
showCancel: false
})
return
}
const index = this.teamList.findIndex(t => t.id === item.id) const index = this.teamList.findIndex(t => t.id === item.id)
if (index !== -1) { if (index !== -1) {
this.$set(this.teamList[index], 'selected', !this.teamList[index].selected) this.$set(this.teamList[index], 'selected', !this.teamList[index].selected)
@@ -564,6 +680,12 @@ export default {
return return
} }
// 强制验证联系人是否已选择
if (!this.selectedContact) {
uni.showToast({ title: '请选择联系人', icon: 'none' })
return
}
const now = new Date() const now = new Date()
const orderNo = `BM${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}${String(Math.floor(Math.random() * 10000)).padStart(4, '0')}` const orderNo = `BM${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}${String(Math.floor(Math.random() * 10000)).padStart(4, '0')}`
@@ -799,6 +921,24 @@ export default {
font-weight: bold; font-weight: bold;
color: #333333; color: #333333;
margin-bottom: 10rpx; margin-bottom: 10rpx;
display: flex;
align-items: center;
gap: 10rpx;
}
.registered-tag {
font-size: 22rpx;
font-weight: normal;
color: #ff6600;
background: #fff3e6;
padding: 4rpx 12rpx;
border-radius: 6rpx;
border: 1px solid #ff6600;
}
.player-item.registered {
opacity: 0.7;
background: #f9f9f9;
} }
.player-id { .player-id {
@@ -341,7 +341,7 @@ export default {
}, },
goToEventDetail(item) { goToEventDetail(item) {
uni.navigateTo({ uni.navigateTo({
url: '/pages/event-detail/event-detail?id=' + item.competitionId url: '/pages/event-detail/event-detail?id=' + item.competitionId + '&orderId=' + item.id
}); });
}, },
handleViewCert(item) { handleViewCert(item) {