update:赛事报名先选择团队
This commit is contained in:
parent
9f92b4da87
commit
1c36e46c4f
@ -357,18 +357,59 @@
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<!-- 赛事报名三步弹窗 -->
|
||||
<!-- 赛事报名四步弹窗 -->
|
||||
<el-dialog title="赛事报名" v-model="isShowRegisterDialog" width="900px" :close-on-click-modal="false"
|
||||
@closed="clearRegisterState">
|
||||
<el-steps :active="activeStep" finish-status="success" align-center>
|
||||
<el-step title="选择团队" />
|
||||
<el-step title="选择报名项目" />
|
||||
<el-step title="分配队员" />
|
||||
<el-step title="预览支付" />
|
||||
</el-steps>
|
||||
|
||||
<div class="register-step-content">
|
||||
<!-- Step 1 -->
|
||||
<!-- Step 1: 选择团队 -->
|
||||
<div v-if="activeStep === 0">
|
||||
<el-skeleton v-if="teamListLoading" :rows="6" animated />
|
||||
<template v-else>
|
||||
<div class="team-select-section">
|
||||
<div class="team-select-label">请选择您的团队:</div>
|
||||
<el-select v-model="selectedTeamId" placeholder="请选择团队" style="width: 100%; max-width: 400px;"
|
||||
@change="onTeamChange" filterable>
|
||||
<el-option v-for="t in teamList" :key="t.id" :label="t.name" :value="t.id" />
|
||||
</el-select>
|
||||
</div>
|
||||
<!-- 团队成员详情 -->
|
||||
<template v-if="selectedTeamId">
|
||||
<el-skeleton v-if="teamMemberLoading" :rows="4" animated style="margin-top: 20px;" />
|
||||
<template v-else>
|
||||
<div class="team-members-detail" v-if="teamMembers.length > 0">
|
||||
<div class="team-members-detail-title">团队成员({{ teamMembers.length }} 人)</div>
|
||||
<div class="team-members-detail-grid">
|
||||
<div v-for="m in teamMembers" :key="m.userId ?? m.id" class="team-member-detail-card">
|
||||
<div class="team-member-detail-name">{{ m.name }}</div>
|
||||
<div class="team-member-detail-info">{{ formatGender(m.gender) }}</div>
|
||||
<div class="team-member-detail-info" v-if="m.birthDate">{{ m.birthDate.slice(0, 10) }}</div>
|
||||
<div class="team-member-detail-mobile" v-if="m.mobile">{{ m.mobile }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else description="该团队暂无运动员" :image-size="60" style="margin-top: 20px;" />
|
||||
</template>
|
||||
</template>
|
||||
<el-empty v-else description="请先选择团队,查看团队成员" :image-size="60" style="margin-top: 20px;" />
|
||||
<!-- 底部操作区域 -->
|
||||
<div class="step-footer" style="display: flex; justify-content: flex-end; margin-top: 20px;">
|
||||
<el-button @click="isShowRegisterDialog = false" style="margin-right: 10px;">取消</el-button>
|
||||
<el-button type="primary" @click="handleStep0Next" :disabled="!selectedTeamId || teamMemberLoading">
|
||||
下一步
|
||||
</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Step 2: 选择报名项目 -->
|
||||
<div v-else-if="activeStep === 1">
|
||||
<el-empty v-if="!registerLoading && !(projects?.length ?? 0)" description="暂无报名项目" />
|
||||
<el-skeleton v-else-if="registerLoading" :rows="8" animated />
|
||||
<template v-else>
|
||||
@ -412,6 +453,7 @@
|
||||
<!-- 底部操作区域 -->
|
||||
<div class="step-footer" style="display: flex; justify-content: flex-end; margin-top: 20px;">
|
||||
<el-button @click="isShowRegisterDialog = false" style="margin-right: 10px;">取消</el-button>
|
||||
<el-button @click="handlePrevious" style="margin-right: 10px;">上一步</el-button>
|
||||
<el-button type="primary" @click="handleStep1Next" :loading="registerLoading">
|
||||
下一步
|
||||
</el-button>
|
||||
@ -419,8 +461,8 @@
|
||||
</template>
|
||||
</div>
|
||||
|
||||
<!-- Step 2 -->
|
||||
<div v-else-if="activeStep === 1">
|
||||
<!-- Step 3: 分配队员 -->
|
||||
<div v-else-if="activeStep === 2">
|
||||
<div class="step2-layout">
|
||||
<!-- 左侧:已选组别,每个组别可分配队员 -->
|
||||
<div class="step2-left">
|
||||
@ -508,18 +550,12 @@
|
||||
<el-empty v-if="!selectedGroupItems.length" description="请先在第一步选择报名组别" />
|
||||
</div>
|
||||
|
||||
<!-- 右侧:团队选择器 + 成员列表 -->
|
||||
<!-- 右侧:成员列表 -->
|
||||
<div class="step2-right">
|
||||
<div class="team-selector">
|
||||
<el-select v-model="selectedTeamId" placeholder="请选择团队" style="width: 100%;"
|
||||
@change="onTeamChange" :loading="teamListLoading" filterable>
|
||||
<el-option v-for="t in teamList" :key="t.id" :label="t.name" :value="t.id" />
|
||||
</el-select>
|
||||
</div>
|
||||
<div class="team-members-panel">
|
||||
<el-skeleton v-if="teamMemberLoading" :rows="6" animated />
|
||||
<el-empty v-else-if="!teamMembers.length"
|
||||
:description="selectedTeamId ? '该团队暂无运动员' : '请先选择团队'" :image-size="60" />
|
||||
:description="'该团队暂无运动员'" :image-size="60" />
|
||||
<template v-else>
|
||||
<div v-for="m in teamMembers" :key="m.userId ?? m.id" class="team-member-tag"
|
||||
:class="{ 'team-member-tag-assigned': isMemberAssignedToActive(m.userId ?? m.id) }"
|
||||
@ -562,8 +598,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Step 3 -->
|
||||
<div v-else-if="activeStep === 2">
|
||||
<!-- Step 4: 预览支付 -->
|
||||
<div v-else-if="activeStep === 3">
|
||||
<el-skeleton :rows="10" animated v-if="previewLoading" />
|
||||
<template v-else>
|
||||
<!-- 银行转账信息显示区域 -->
|
||||
@ -1227,7 +1263,7 @@ const toggleGroupSelection = (id) => {
|
||||
// 取消选中
|
||||
selectedGroupIds.value.splice(idx, 1);
|
||||
// 若在第二步删除了组别,清理该组别的验证缓存并重新触发验证
|
||||
if (activeStep.value === 1) {
|
||||
if (activeStep.value === 2) {
|
||||
// 清理被删除组别的队员验证缓存
|
||||
Object.keys(memberValidationMap.value).forEach(key => {
|
||||
if (key.startsWith(`${id}_`)) {
|
||||
@ -1239,14 +1275,14 @@ const toggleGroupSelection = (id) => {
|
||||
}
|
||||
} else {
|
||||
// 选中新组别:先找出这个组别属于哪个项目,然后取消该项目的其他组别
|
||||
const clickedGroup = allGroups.value.find(g => g.id === id);
|
||||
if (clickedGroup && clickedGroup.projectId) {
|
||||
// 移除同一项目下的其他组别
|
||||
selectedGroupIds.value = selectedGroupIds.value.filter(selectedId => {
|
||||
const selectedGroup = allGroups.value.find(g => g.id === selectedId);
|
||||
return selectedGroup?.projectId !== clickedGroup.projectId;
|
||||
});
|
||||
}
|
||||
// const clickedGroup = allGroups.value.find(g => g.id === id);
|
||||
// if (clickedGroup && clickedGroup.projectId) {
|
||||
// // 移除同一项目下的其他组别
|
||||
// selectedGroupIds.value = selectedGroupIds.value.filter(selectedId => {
|
||||
// const selectedGroup = allGroups.value.find(g => g.id === selectedId);
|
||||
// return selectedGroup?.projectId !== clickedGroup.projectId;
|
||||
// });
|
||||
// }
|
||||
// 添加新选中的组别
|
||||
selectedGroupIds.value.push(id);
|
||||
}
|
||||
@ -1475,6 +1511,8 @@ const openRegistrationDialog = async (row) => {
|
||||
paymentMethod.value = 1;
|
||||
isShowRegisterDialog.value = true;
|
||||
activeStep.value = 0;
|
||||
// 加载团队列表(第一步需要展示)
|
||||
fetchTeamList();
|
||||
} catch (error) {
|
||||
console.error('打开报名弹窗失败:', error);
|
||||
ElMessage.error('项目加载失败');
|
||||
@ -1531,7 +1569,8 @@ const onTeamChange = async (teamId) => {
|
||||
mobile: m.mobile ?? '',
|
||||
gender: m.gender ?? '',
|
||||
role: m.role ?? '',
|
||||
teamId: teamId, // 添加团队ID
|
||||
birthDate: m.birthDate ?? m.birthday ?? '',
|
||||
teamId: teamId,
|
||||
}));
|
||||
}
|
||||
} catch {
|
||||
@ -1590,7 +1629,7 @@ const validateMemberForGroup = async (member, group) => {
|
||||
|
||||
// 实时验证所有已选择的队员
|
||||
const validateAllMembers = async () => {
|
||||
if (!currentEventId.value || activeStep.value !== 1) {
|
||||
if (!currentEventId.value || activeStep.value !== 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -2050,16 +2089,21 @@ const fetchMembers = async () => {
|
||||
};
|
||||
|
||||
const handlePrevious = () => {
|
||||
if (activeStep.value === 2) {
|
||||
activeStep.value = 1;
|
||||
if (activeStep.value === 3) {
|
||||
activeStep.value = 2;
|
||||
previewData.value = null;
|
||||
previewLoading.value = false;
|
||||
draftRegistrationId.value = null;
|
||||
return;
|
||||
}
|
||||
if (activeStep.value === 2) {
|
||||
activeStep.value = 1;
|
||||
resetAssignMembersAndBeyond();
|
||||
return;
|
||||
}
|
||||
if (activeStep.value === 1) {
|
||||
activeStep.value = 0;
|
||||
resetStep2AndBeyond();
|
||||
selectedGroupIds.value = [];
|
||||
return;
|
||||
}
|
||||
};
|
||||
@ -2185,20 +2229,42 @@ const checkRegistrationLimit = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
// 重置第三步(分配队员)及之后的状态,保留团队选择数据
|
||||
const resetAssignMembersAndBeyond = () => {
|
||||
activeAssignGroupId.value = null;
|
||||
groupMemberMap.value = {};
|
||||
usedTeamId.value = null;
|
||||
groupTeamsMap.value = {};
|
||||
activeTeamKey.value = null;
|
||||
groupMaxTeamsMap.value = {};
|
||||
previewData.value = null;
|
||||
previewLoading.value = false;
|
||||
draftRegistrationId.value = null;
|
||||
memberValidationMap.value = {};
|
||||
registrationLimitCheckResult.value = null;
|
||||
};
|
||||
|
||||
const handleStep0Next = () => {
|
||||
if (!selectedTeamId.value) {
|
||||
ElMessage.warning('请先选择团队');
|
||||
return;
|
||||
}
|
||||
activeStep.value = 1;
|
||||
};
|
||||
|
||||
const handleStep1Next = async () => {
|
||||
if (!(selectedGroupIds.value?.length ?? 0)) {
|
||||
ElMessage.warning('请先选择报名组别');
|
||||
return;
|
||||
}
|
||||
|
||||
activeStep.value = 1;
|
||||
resetStep2AndBeyond();
|
||||
activeStep.value = 2;
|
||||
resetAssignMembersAndBeyond();
|
||||
// 默认激活第一个组别
|
||||
if (selectedGroupItems.value.length > 0) {
|
||||
activeAssignGroupId.value = selectedGroupItems.value[0].id;
|
||||
}
|
||||
// 加载团队列表
|
||||
await fetchTeamList();
|
||||
// 团队已在第一步选择,无需再次加载团队列表
|
||||
// 加载队伍限制配置
|
||||
await fetchGroupTeamLimit();
|
||||
|
||||
@ -2334,7 +2400,7 @@ const handleStep2Next = async () => {
|
||||
}
|
||||
draftRegistrationId.value = data;
|
||||
|
||||
activeStep.value = 2;
|
||||
activeStep.value = 3;
|
||||
previewLoading.value = true;
|
||||
try {
|
||||
const { succeeded: pOk, data: pData } = await usereventregistrationPreviewGet(data);
|
||||
@ -4006,4 +4072,74 @@ const handleCreateOrderAndPay = async () => {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* ---- 第一步:选择团队 ---- */
|
||||
.team-select-section {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 14px;
|
||||
padding: 20px 0 8px;
|
||||
}
|
||||
|
||||
.team-select-label {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.team-members-detail {
|
||||
margin-top: 20px;
|
||||
border: 1px solid #e0ecfd;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.team-members-detail-title {
|
||||
padding: 10px 16px;
|
||||
background: linear-gradient(90deg, #eef5ff 0%, #f8fbff 100%);
|
||||
border-bottom: 1px solid #e0ecfd;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #1a3c6e;
|
||||
}
|
||||
|
||||
.team-members-detail-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||||
gap: 10px;
|
||||
padding: 14px 16px;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.team-member-detail-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 4px;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #e0ecfd;
|
||||
border-radius: 8px;
|
||||
background: #f8fbff;
|
||||
transition: box-shadow 0.2s;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 2px 8px rgba(64, 158, 255, 0.12);
|
||||
}
|
||||
}
|
||||
|
||||
.team-member-detail-name {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: #303133;
|
||||
}
|
||||
|
||||
.team-member-detail-info {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
|
||||
.team-member-detail-mobile {
|
||||
font-size: 12px;
|
||||
color: #909399;
|
||||
}
|
||||
</style>
|
||||
Loading…
x
Reference in New Issue
Block a user