fix: 选手列表去重并显示已报名标记

- loadPlayerList 添加按身份证去重逻辑
- 查询已报名选手并标记 hasRegistered
- UI 显示"已报名"标签
- 选择已报名选手时弹出警告

Closes #3, Closes #4
This commit is contained in:
DevOps
2026-01-15 15:56:44 +08:00
parent 076aa287bd
commit 82deb8b4f9
2 changed files with 78 additions and 8 deletions
+7
View File
@@ -81,5 +81,12 @@ export default {
removeContact(id) {
return request.post('/martial/contact/remove?ids=' + id, {})
},
/**
* 获取已报名选手列表(用于检查重复报名)
*/
getRegisteredAthletes(params = {}) {
return request.get('/martial/athlete/registered', params)
}
}
+71 -8
View File
@@ -30,13 +30,16 @@
</view>
<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)">
<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>
</view>
<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>
<view class="player-actions">
@@ -426,12 +429,43 @@ export default {
})
let list = res.records || (Array.isArray(res) ? res : [])
this.playerList = list.map(item => ({
id: item.id,
name: item.name || item.athleteName || item.playerName || '未命名',
idCard: item.idCard || item.idCardNumber || '',
selected: false
}))
// Deduplicate by idCard
const seen = new Set()
list = list.filter(item => {
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) {
console.error('加载选手列表失败:', err)
}
@@ -478,6 +512,17 @@ export default {
},
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)
if (index !== -1) {
this.$set(this.playerList[index], 'selected', !this.playerList[index].selected)
@@ -830,6 +875,24 @@ export default {
font-weight: bold;
color: #333333;
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 {