feat: 竞赛分组页面添加队伍展开功能,显示选手签到状态和异常标记
- 点击队伍行可展开显示选手详情 - 显示选手签到状态:未签到/已签到/异常 - 支持标记异常和取消异常操作 - 优化评分页面代码 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -71,69 +71,87 @@
|
||||
</el-button>
|
||||
</div>
|
||||
|
||||
<div v-for="(group, index) in filteredCompetitionGroups" :key="group.id" class="competition-group">
|
||||
<div class="group-header">
|
||||
<div class="group-info">
|
||||
<span class="group-title">{{ group.title }}</span>
|
||||
<span class="group-meta">{{ group.type }}</span>
|
||||
<span class="group-meta">{{ group.count }}</span>
|
||||
<span class="group-meta">{{ group.code }}</span>
|
||||
<!-- 项目卡片列表 -->
|
||||
<div v-for="(group, groupIndex) in filteredCompetitionGroups" :key="group.id" class="project-card">
|
||||
<!-- 项目头部 -->
|
||||
<div class="project-header">
|
||||
<div class="project-info">
|
||||
<span class="project-index">{{ groupIndex + 1 }}、</span>
|
||||
<span class="project-title">{{ group.title }}</span>
|
||||
<span class="project-meta">{{ group.type }}</span>
|
||||
<span class="project-meta">{{ getTeamCount(group) }}队</span>
|
||||
<span class="project-meta">{{ group.items?.length || 0 }}组</span>
|
||||
<span class="project-meta">{{ group.code }}</span>
|
||||
</div>
|
||||
<div class="group-actions">
|
||||
<el-button size="small" type="warning" @click="handleMoveGroup(group)">
|
||||
<div class="project-actions">
|
||||
<el-popover
|
||||
placement="bottom"
|
||||
:width="200"
|
||||
trigger="click"
|
||||
:disabled="isScheduleCompleted"
|
||||
>
|
||||
<template #reference>
|
||||
<el-button size="small" type="warning" :disabled="isScheduleCompleted">
|
||||
移动
|
||||
</el-button>
|
||||
</template>
|
||||
<div class="move-popover">
|
||||
<div class="move-label">移动到</div>
|
||||
<el-select v-model="moveTargetVenueId" placeholder="选择场地" size="small" style="width: 100%; margin-bottom: 10px;">
|
||||
<el-option
|
||||
v-for="venue in venues"
|
||||
:key="venue.id"
|
||||
:label="venue.venueName"
|
||||
:value="venue.id"
|
||||
></el-option>
|
||||
</el-select>
|
||||
<el-button size="small" type="primary" @click="quickMoveGroup(group)">移动</el-button>
|
||||
</div>
|
||||
</el-popover>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-table :data="groupItemsByTeam(group.items)" border stripe size="small" row-key="id">
|
||||
<!-- 展开列 -->
|
||||
<el-table-column type="expand" width="30">
|
||||
<template #default="{ row }">
|
||||
<div v-if="row.players.length > 1" class="player-expand-list">
|
||||
<div v-for="player in row.players" :key="player.id" class="player-row">
|
||||
<span class="player-name">{{ player.playerName }}</span>
|
||||
<el-tag :type="player.status === '已签到' ? 'success' : player.status === '异常' ? 'danger' : 'info'" size="small">
|
||||
{{ player.status || '未签到' }}
|
||||
</el-tag>
|
||||
<el-button
|
||||
v-if="(player.status || '未签到') === '未签到'"
|
||||
link
|
||||
size="small"
|
||||
@click="markPlayerAsException(group, player)"
|
||||
:disabled="isScheduleCompleted"
|
||||
style="color: #f56c6c;"
|
||||
<!-- 队伍列表 -->
|
||||
<div class="team-list">
|
||||
<div
|
||||
v-for="(team, teamIndex) in groupItemsByTeam(group.items)"
|
||||
:key="team.id"
|
||||
class="team-row"
|
||||
:class="{ 'team-row-expanded': isTeamExpanded(group.id, team.id) }"
|
||||
>
|
||||
异常
|
||||
</el-button>
|
||||
<!-- 队伍主行 - 可点击展开 -->
|
||||
<div class="team-main" @click="toggleTeamExpand(group.id, team.id)">
|
||||
<!-- 展开图标 -->
|
||||
<span class="expand-icon">
|
||||
<el-icon v-if="isTeamExpanded(group.id, team.id)"><ArrowDown /></el-icon>
|
||||
<el-icon v-else><ArrowRight /></el-icon>
|
||||
</span>
|
||||
|
||||
<!-- 队伍信息 -->
|
||||
<div class="team-info">
|
||||
<span class="team-index">{{ teamIndex + 1 }}、</span>
|
||||
<span class="team-name">{{ team.schoolUnit }}</span>
|
||||
</div>
|
||||
|
||||
<!-- 选手列表 -->
|
||||
<div class="player-list">
|
||||
<span
|
||||
v-for="(player, playerIndex) in team.players"
|
||||
:key="player.id"
|
||||
class="player-tag"
|
||||
:class="{ 'player-exception': player.status === '异常' }"
|
||||
>
|
||||
{{ player.playerName }}
|
||||
</span>
|
||||
</div>
|
||||
<div v-else class="player-expand-list">
|
||||
<span style="color: #909399;">单人队伍</span>
|
||||
</div>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="序号" type="index" width="60" align="center"></el-table-column>
|
||||
<el-table-column prop="schoolUnit" label="学校/单位" min-width="150"></el-table-column>
|
||||
<el-table-column label="选手" min-width="120">
|
||||
<template #default="{ row }">
|
||||
{{ row.players.map(p => p.playerName).join('、') }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="状态" width="100" align="center">
|
||||
<template #default="{ row }">
|
||||
<el-tag :type="getTeamStatusType(row)" size="small">
|
||||
{{ getTeamStatus(row) }}
|
||||
</el-tag>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column label="操作" width="150" align="center">
|
||||
<template #default="scope">
|
||||
|
||||
<!-- 操作按钮 -->
|
||||
<div class="team-actions" @click.stop>
|
||||
<el-button
|
||||
link
|
||||
size="small"
|
||||
@click="handleTeamMoveUp(group, scope.$index)"
|
||||
:disabled="scope.$index === 0 || isScheduleCompleted"
|
||||
@click="handleTeamMoveUp(group, teamIndex)"
|
||||
:disabled="teamIndex === 0 || isScheduleCompleted"
|
||||
title="上移"
|
||||
class="move-btn"
|
||||
>
|
||||
@@ -142,26 +160,59 @@
|
||||
<el-button
|
||||
link
|
||||
size="small"
|
||||
@click="handleTeamMoveDown(group, scope.$index)"
|
||||
:disabled="scope.$index === groupItemsByTeam(group.items).length - 1 || isScheduleCompleted"
|
||||
@click="handleTeamMoveDown(group, teamIndex)"
|
||||
:disabled="teamIndex === groupItemsByTeam(group.items).length - 1 || isScheduleCompleted"
|
||||
title="下移"
|
||||
class="move-btn"
|
||||
>
|
||||
<img src="/img/图标 4@3x.png" class="move-icon" alt="下移" />
|
||||
</el-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 展开内容 - 选手详情 -->
|
||||
<div v-if="isTeamExpanded(group.id, team.id)" class="team-expand-content">
|
||||
<div
|
||||
v-for="(player, playerIndex) in team.players"
|
||||
:key="player.id"
|
||||
class="player-detail-row"
|
||||
>
|
||||
<span class="player-detail-index">{{ playerIndex + 1 }}</span>
|
||||
<span class="player-detail-name">{{ player.playerName }}</span>
|
||||
<span class="player-detail-status">
|
||||
<el-tag
|
||||
:type="player.status === '已签到' ? 'success' : player.status === '异常' ? 'danger' : 'info'"
|
||||
size="small"
|
||||
>
|
||||
{{ player.status || '未签到' }}
|
||||
</el-tag>
|
||||
</span>
|
||||
<span class="player-detail-actions">
|
||||
<el-button
|
||||
v-if="scope.row.players.length === 1 && (scope.row.players[0].status || '未签到') === '未签到'"
|
||||
v-if="(player.status || '未签到') === '未签到'"
|
||||
link
|
||||
size="small"
|
||||
@click="markPlayerAsException(group, scope.row.players[0])"
|
||||
@click="markPlayerAsException(group, team, playerIndex)"
|
||||
:disabled="isScheduleCompleted"
|
||||
style="color: #f56c6c;"
|
||||
>
|
||||
异常
|
||||
标记异常
|
||||
</el-button>
|
||||
</template>
|
||||
</el-table-column>
|
||||
</el-table>
|
||||
<el-button
|
||||
v-if="player.status === '异常'"
|
||||
link
|
||||
size="small"
|
||||
@click="removePlayerException(group, team, playerIndex)"
|
||||
:disabled="isScheduleCompleted"
|
||||
style="color: #67c23a;"
|
||||
>
|
||||
取消异常
|
||||
</el-button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -303,12 +354,17 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ArrowDown, ArrowRight } from '@element-plus/icons-vue'
|
||||
import { getVenuesByCompetition } from '@/api/martial/venue'
|
||||
import { getCompetitionDetail } from '@/api/martial/competition'
|
||||
import { getScheduleResult, saveAndLockSchedule, saveDraftSchedule, triggerAutoArrange, moveScheduleGroup } from '@/api/martial/activitySchedule'
|
||||
|
||||
export default {
|
||||
name: 'MartialScheduleList',
|
||||
components: {
|
||||
ArrowDown,
|
||||
ArrowRight
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
competitionId: null,
|
||||
@@ -337,7 +393,8 @@ export default {
|
||||
|
||||
// 异常组相关
|
||||
exceptionDialogVisible: false,
|
||||
exceptionList: [] // 异常参赛人员列表
|
||||
exceptionList: [], // 异常参赛人员列表
|
||||
expandedTeams: {} // 展开的队伍 { 'groupId-teamId': true }
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
@@ -403,6 +460,59 @@ export default {
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 检查队伍是否展开
|
||||
isTeamExpanded(groupId, teamId) {
|
||||
const key = groupId + '-' + teamId
|
||||
return this.expandedTeams[key] === true
|
||||
},
|
||||
|
||||
// 切换队伍展开状态
|
||||
toggleTeamExpand(groupId, teamId) {
|
||||
const key = groupId + '-' + teamId
|
||||
if (this.expandedTeams[key]) {
|
||||
delete this.expandedTeams[key]
|
||||
} else {
|
||||
this.expandedTeams[key] = true
|
||||
}
|
||||
// 触发响应式更新
|
||||
this.expandedTeams = { ...this.expandedTeams }
|
||||
},
|
||||
|
||||
// 标记选手为异常
|
||||
markPlayerAsException(group, team, playerIndex) {
|
||||
const player = team.players[playerIndex]
|
||||
if (player) {
|
||||
player.status = '异常'
|
||||
// 添加到异常列表
|
||||
this.exceptionList.push({
|
||||
groupId: group.id,
|
||||
groupTitle: group.title,
|
||||
teamId: team.id,
|
||||
schoolUnit: team.schoolUnit,
|
||||
playerId: player.id,
|
||||
playerName: player.playerName,
|
||||
status: '异常'
|
||||
})
|
||||
this.$message.success('已标记为异常')
|
||||
}
|
||||
},
|
||||
|
||||
// 取消选手异常状态
|
||||
removePlayerException(group, team, playerIndex) {
|
||||
const player = team.players[playerIndex]
|
||||
if (player) {
|
||||
player.status = '未签到'
|
||||
// 从异常列表中移除
|
||||
const idx = this.exceptionList.findIndex(
|
||||
e => e.playerId === player.id && e.groupId === group.id
|
||||
)
|
||||
if (idx !== -1) {
|
||||
this.exceptionList.splice(idx, 1)
|
||||
}
|
||||
this.$message.success('已取消异常标记')
|
||||
}
|
||||
},
|
||||
|
||||
// 将选手按学校/单位分组为队伍
|
||||
groupItemsByTeam(items) {
|
||||
if (!items || items.length === 0) return []
|
||||
@@ -423,6 +533,45 @@ export default {
|
||||
return Array.from(teamMap.values())
|
||||
},
|
||||
|
||||
// 获取队伍数量
|
||||
getTeamCount(group) {
|
||||
if (!group.items || group.items.length === 0) return 0
|
||||
const teams = this.groupItemsByTeam(group.items)
|
||||
return teams.length
|
||||
},
|
||||
|
||||
// 快速移动分组(从popover中调用)
|
||||
async quickMoveGroup(group) {
|
||||
if (!this.moveTargetVenueId) {
|
||||
this.$message.warning('请选择目标场地')
|
||||
return
|
||||
}
|
||||
|
||||
const targetVenue = this.venues.find(v => v.id === this.moveTargetVenueId)
|
||||
|
||||
try {
|
||||
// 调用后端API移动分组
|
||||
const res = await moveScheduleGroup({
|
||||
groupId: group.id,
|
||||
targetVenueId: this.moveTargetVenueId,
|
||||
targetTimeSlotIndex: this.selectedTime // 保持当前时间段
|
||||
})
|
||||
|
||||
if (res.data.success) {
|
||||
// 更新前端数据
|
||||
group.venueId = this.moveTargetVenueId
|
||||
group.venueName = targetVenue ? targetVenue.venueName : ''
|
||||
|
||||
this.$message.success(`已移动到 ${group.venueName}`)
|
||||
} else {
|
||||
this.$message.error(res.data.msg || '移动分组失败')
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('移动分组失败:', error)
|
||||
this.$message.error('移动分组失败,请稍后重试')
|
||||
}
|
||||
},
|
||||
|
||||
// 获取队伍状态
|
||||
getTeamStatus(team) {
|
||||
if (!team || !team.players) return '未签到'
|
||||
@@ -1117,6 +1266,178 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
// 新的项目卡片样式
|
||||
.project-card {
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
|
||||
.project-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 16px;
|
||||
background: #fafafa;
|
||||
border-bottom: 1px solid #e4e7ed;
|
||||
|
||||
.project-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
|
||||
.project-index {
|
||||
font-weight: 600;
|
||||
color: #e6a23c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.project-title {
|
||||
font-weight: 600;
|
||||
color: #e6a23c;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.project-meta {
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.project-actions {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.team-list {
|
||||
.team-row {
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
background: #fff;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
&.team-row-expanded {
|
||||
background: #fafafa;
|
||||
}
|
||||
|
||||
.team-main {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 12px 16px;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
background: #f5f7fa;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
width: 20px;
|
||||
color: #909399;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.team-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
min-width: 180px;
|
||||
|
||||
.team-index {
|
||||
color: #909399;
|
||||
font-size: 13px;
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.team-name {
|
||||
color: #303133;
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.player-list {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 8px;
|
||||
padding: 0 20px;
|
||||
|
||||
.player-tag {
|
||||
color: #606266;
|
||||
font-size: 13px;
|
||||
padding: 2px 8px;
|
||||
background: #f4f4f5;
|
||||
border-radius: 4px;
|
||||
|
||||
&.player-exception {
|
||||
color: #f56c6c;
|
||||
background: #fef0f0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.team-actions {
|
||||
display: flex;
|
||||
gap: 4px;
|
||||
min-width: 80px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
}
|
||||
|
||||
.team-expand-content {
|
||||
background: #fafafa;
|
||||
border-top: 1px dashed #e4e7ed;
|
||||
padding: 8px 16px 8px 56px;
|
||||
|
||||
.player-detail-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 8px 12px;
|
||||
border-bottom: 1px solid #ebeef5;
|
||||
|
||||
&:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.player-detail-index {
|
||||
width: 30px;
|
||||
color: #909399;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.player-detail-name {
|
||||
flex: 1;
|
||||
color: #303133;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.player-detail-status {
|
||||
width: 80px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.player-detail-actions {
|
||||
width: 100px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.move-popover {
|
||||
.move-label {
|
||||
font-size: 13px;
|
||||
color: #606266;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.group-footer-hints {
|
||||
margin-top: 15px;
|
||||
padding: 8px 12px;
|
||||
|
||||
@@ -154,6 +154,11 @@
|
||||
<div class="total-score-display">
|
||||
<span class="label">总分:</span>
|
||||
<span class="value">{{ formatScore(currentDetail.totalScore) }}</span>
|
||||
<div class="calculation-note">
|
||||
<span v-if="currentDetail.judgeScores.length > 2">
|
||||
(去掉最高分和最低分后的平均分)
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -182,96 +187,6 @@ export default {
|
||||
projectOptions: [],
|
||||
venueOptions: [],
|
||||
scoreList: [],
|
||||
allTableData: [
|
||||
{
|
||||
id: 1,
|
||||
projectName: '男子组陈氏太极拳',
|
||||
venueName: '第一场地',
|
||||
playerName: '张三',
|
||||
teamName: '少林寺武术大学院',
|
||||
idCard: '123456789000000000',
|
||||
playerNo: '123-4567898275',
|
||||
judgeScores: [8.906, 8.905, 8.908, 8.907, 8.906],
|
||||
totalScore: 8.907
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
projectName: '女子组长拳',
|
||||
venueName: '第一场地',
|
||||
playerName: '李四',
|
||||
teamName: '武当武术学院',
|
||||
idCard: '123456789000000001',
|
||||
playerNo: '123-4567898276',
|
||||
judgeScores: [9.125, 9.130, 9.128, 9.126, 9.129],
|
||||
totalScore: 9.128
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
projectName: '男子组陈氏太极拳',
|
||||
venueName: '第二场地',
|
||||
playerName: '王五',
|
||||
teamName: '峨眉武术协会',
|
||||
idCard: '123456789000000002',
|
||||
playerNo: '123-4567898277',
|
||||
judgeScores: [8.550, 8.548, 8.552, 8.551, 8.549],
|
||||
totalScore: 8.550
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
projectName: '女子组双剑(含长穗双剑)',
|
||||
venueName: '第一场地',
|
||||
playerName: '赵六',
|
||||
teamName: '昆仑武术馆',
|
||||
idCard: '123456789000000003',
|
||||
playerNo: '123-4567898278',
|
||||
judgeScores: [9.245, 9.248, 9.246, 9.247, 9.249],
|
||||
totalScore: 9.247
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
projectName: '男子组杨氏太极拳',
|
||||
venueName: '第三场地',
|
||||
playerName: '孙七',
|
||||
teamName: '华山武术学校',
|
||||
idCard: '123456789000000004',
|
||||
playerNo: '123-4567898279',
|
||||
judgeScores: [8.785, 8.788, 8.786, 8.787, 8.785],
|
||||
totalScore: 8.786
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
projectName: '女子组刀术',
|
||||
venueName: '第二场地',
|
||||
playerName: '周八',
|
||||
teamName: '少林寺武术大学院',
|
||||
idCard: '123456789000000005',
|
||||
playerNo: '123-4567898280',
|
||||
judgeScores: [8.925, 8.928, 8.926, 8.927, 8.925],
|
||||
totalScore: 8.926
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
projectName: '男子组棍术',
|
||||
venueName: '第四场地',
|
||||
playerName: '吴九',
|
||||
teamName: '武当武术学院',
|
||||
idCard: '123456789000000006',
|
||||
playerNo: '123-4567898281',
|
||||
judgeScores: [9.015, 9.018, 9.016, 9.017, 9.015],
|
||||
totalScore: 9.016
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
projectName: '女子组枪术',
|
||||
venueName: '第三场地',
|
||||
playerName: '郑十',
|
||||
teamName: '峨眉武术协会',
|
||||
idCard: '123456789000000007',
|
||||
playerNo: '123-4567898282',
|
||||
judgeScores: [8.665, 8.668, 8.666, 8.667, 8.665],
|
||||
totalScore: 8.666
|
||||
}
|
||||
],
|
||||
tableData: [],
|
||||
pagination: {
|
||||
current: 1,
|
||||
@@ -345,25 +260,22 @@ export default {
|
||||
try {
|
||||
const res = await getScoreList(this.pagination.current, this.pagination.size, params)
|
||||
console.log('评分列表返回数据:', res)
|
||||
console.log('===== 调试:后端返回的数据结构 =====')
|
||||
const responseData = res.data?.data
|
||||
if (responseData && responseData.records && responseData.records.length > 0) {
|
||||
console.log('第一条评分记录:', responseData.records[0])
|
||||
console.log('记录字段:', Object.keys(responseData.records[0]))
|
||||
console.log('是否包含 projectName:', 'projectName' in responseData.records[0])
|
||||
console.log('是否包含 venueName:', 'venueName' in responseData.records[0])
|
||||
console.log('是否包含 playerName:', 'playerName' in responseData.records[0])
|
||||
console.log('projectId 值:', responseData.records[0].projectId)
|
||||
console.log('venueId 值:', responseData.records[0].venueId)
|
||||
console.log('athleteId 值:', responseData.records[0].athleteId)
|
||||
}
|
||||
console.log('======================================')
|
||||
|
||||
const responseData = res.data?.data
|
||||
if (responseData && responseData.records) {
|
||||
this.scoreList = responseData.records
|
||||
// 过滤掉 projectId 为 null 的无效记录
|
||||
const validScores = responseData.records.filter(score => {
|
||||
if (!score.projectId) {
|
||||
console.warn('发现无效评分记录(projectId为空):', score)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
this.scoreList = validScores
|
||||
|
||||
// 补充关联数据(项目名称、场地名称、选手名称)
|
||||
await this.enrichScoreData(responseData.records)
|
||||
await this.enrichScoreData(validScores)
|
||||
|
||||
// 按选手分组评分数据
|
||||
this.processScoreData(this.scoreList)
|
||||
@@ -466,6 +378,12 @@ export default {
|
||||
const athleteMap = new Map()
|
||||
|
||||
scores.forEach(score => {
|
||||
// 确保 projectId 存在
|
||||
if (!score.projectId) {
|
||||
console.warn('跳过无效评分记录:', score)
|
||||
return
|
||||
}
|
||||
|
||||
const key = `${score.athleteId}-${score.projectId}`
|
||||
if (!athleteMap.has(key)) {
|
||||
athleteMap.set(key, {
|
||||
@@ -495,11 +413,10 @@ export default {
|
||||
})
|
||||
})
|
||||
|
||||
// 计算总分(平均分)
|
||||
// 计算总分(去掉最高最低分后的平均分)
|
||||
this.tableData = Array.from(athleteMap.values()).map(athlete => {
|
||||
if (athlete.judgeScores.length > 0) {
|
||||
const sum = athlete.judgeScores.reduce((a, b) => a + b, 0)
|
||||
athlete.totalScore = sum / athlete.judgeScores.length
|
||||
athlete.totalScore = this.calculateFinalScore(athlete.judgeScores)
|
||||
}
|
||||
return athlete
|
||||
})
|
||||
@@ -516,6 +433,34 @@ export default {
|
||||
this.judgeColumns = Array(maxJudges).fill(null)
|
||||
},
|
||||
|
||||
/**
|
||||
* 计算最终得分
|
||||
* 规则:
|
||||
* - 如果裁判数 <= 2,直接取平均值
|
||||
* - 如果裁判数 > 2,去掉最高分和最低分后取平均值
|
||||
*/
|
||||
calculateFinalScore(scores) {
|
||||
if (!scores || scores.length === 0) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// 如果只有1-2个裁判,直接取平均值
|
||||
if (scores.length <= 2) {
|
||||
const sum = scores.reduce((a, b) => a + b, 0)
|
||||
return sum / scores.length
|
||||
}
|
||||
|
||||
// 3个及以上裁判,去掉最高分和最低分
|
||||
const sortedScores = [...scores].sort((a, b) => a - b)
|
||||
|
||||
// 去掉第一个(最低分)和最后一个(最高分)
|
||||
const validScores = sortedScores.slice(1, -1)
|
||||
|
||||
// 计算平均值
|
||||
const sum = validScores.reduce((a, b) => a + b, 0)
|
||||
return sum / validScores.length
|
||||
},
|
||||
|
||||
// 查询
|
||||
handleSearch() {
|
||||
this.pagination.current = 1
|
||||
@@ -663,6 +608,12 @@ export default {
|
||||
font-weight: 700;
|
||||
color: #1b7c5e;
|
||||
}
|
||||
|
||||
.calculation-note {
|
||||
margin-top: 8px;
|
||||
font-size: 12px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user