update:赛事报名先选择团队
This commit is contained in:
parent
9f92b4da87
commit
1c36e46c4f
@ -357,18 +357,59 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 赛事报名三步弹窗 -->
|
<!-- 赛事报名四步弹窗 -->
|
||||||
<el-dialog title="赛事报名" v-model="isShowRegisterDialog" width="900px" :close-on-click-modal="false"
|
<el-dialog title="赛事报名" v-model="isShowRegisterDialog" width="900px" :close-on-click-modal="false"
|
||||||
@closed="clearRegisterState">
|
@closed="clearRegisterState">
|
||||||
<el-steps :active="activeStep" finish-status="success" align-center>
|
<el-steps :active="activeStep" finish-status="success" align-center>
|
||||||
|
<el-step title="选择团队" />
|
||||||
<el-step title="选择报名项目" />
|
<el-step title="选择报名项目" />
|
||||||
<el-step title="分配队员" />
|
<el-step title="分配队员" />
|
||||||
<el-step title="预览支付" />
|
<el-step title="预览支付" />
|
||||||
</el-steps>
|
</el-steps>
|
||||||
|
|
||||||
<div class="register-step-content">
|
<div class="register-step-content">
|
||||||
<!-- Step 1 -->
|
<!-- Step 1: 选择团队 -->
|
||||||
<div v-if="activeStep === 0">
|
<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-empty v-if="!registerLoading && !(projects?.length ?? 0)" description="暂无报名项目" />
|
||||||
<el-skeleton v-else-if="registerLoading" :rows="8" animated />
|
<el-skeleton v-else-if="registerLoading" :rows="8" animated />
|
||||||
<template v-else>
|
<template v-else>
|
||||||
@ -412,6 +453,7 @@
|
|||||||
<!-- 底部操作区域 -->
|
<!-- 底部操作区域 -->
|
||||||
<div class="step-footer" style="display: flex; justify-content: flex-end; 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 @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 type="primary" @click="handleStep1Next" :loading="registerLoading">
|
||||||
下一步
|
下一步
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -419,8 +461,8 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Step 2 -->
|
<!-- Step 3: 分配队员 -->
|
||||||
<div v-else-if="activeStep === 1">
|
<div v-else-if="activeStep === 2">
|
||||||
<div class="step2-layout">
|
<div class="step2-layout">
|
||||||
<!-- 左侧:已选组别,每个组别可分配队员 -->
|
<!-- 左侧:已选组别,每个组别可分配队员 -->
|
||||||
<div class="step2-left">
|
<div class="step2-left">
|
||||||
@ -508,18 +550,12 @@
|
|||||||
<el-empty v-if="!selectedGroupItems.length" description="请先在第一步选择报名组别" />
|
<el-empty v-if="!selectedGroupItems.length" description="请先在第一步选择报名组别" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 右侧:团队选择器 + 成员列表 -->
|
<!-- 右侧:成员列表 -->
|
||||||
<div class="step2-right">
|
<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">
|
<div class="team-members-panel">
|
||||||
<el-skeleton v-if="teamMemberLoading" :rows="6" animated />
|
<el-skeleton v-if="teamMemberLoading" :rows="6" animated />
|
||||||
<el-empty v-else-if="!teamMembers.length"
|
<el-empty v-else-if="!teamMembers.length"
|
||||||
:description="selectedTeamId ? '该团队暂无运动员' : '请先选择团队'" :image-size="60" />
|
:description="'该团队暂无运动员'" :image-size="60" />
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<div v-for="m in teamMembers" :key="m.userId ?? m.id" class="team-member-tag"
|
<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) }"
|
:class="{ 'team-member-tag-assigned': isMemberAssignedToActive(m.userId ?? m.id) }"
|
||||||
@ -562,8 +598,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Step 3 -->
|
<!-- Step 4: 预览支付 -->
|
||||||
<div v-else-if="activeStep === 2">
|
<div v-else-if="activeStep === 3">
|
||||||
<el-skeleton :rows="10" animated v-if="previewLoading" />
|
<el-skeleton :rows="10" animated v-if="previewLoading" />
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<!-- 银行转账信息显示区域 -->
|
<!-- 银行转账信息显示区域 -->
|
||||||
@ -1227,7 +1263,7 @@ const toggleGroupSelection = (id) => {
|
|||||||
// 取消选中
|
// 取消选中
|
||||||
selectedGroupIds.value.splice(idx, 1);
|
selectedGroupIds.value.splice(idx, 1);
|
||||||
// 若在第二步删除了组别,清理该组别的验证缓存并重新触发验证
|
// 若在第二步删除了组别,清理该组别的验证缓存并重新触发验证
|
||||||
if (activeStep.value === 1) {
|
if (activeStep.value === 2) {
|
||||||
// 清理被删除组别的队员验证缓存
|
// 清理被删除组别的队员验证缓存
|
||||||
Object.keys(memberValidationMap.value).forEach(key => {
|
Object.keys(memberValidationMap.value).forEach(key => {
|
||||||
if (key.startsWith(`${id}_`)) {
|
if (key.startsWith(`${id}_`)) {
|
||||||
@ -1239,14 +1275,14 @@ const toggleGroupSelection = (id) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 选中新组别:先找出这个组别属于哪个项目,然后取消该项目的其他组别
|
// 选中新组别:先找出这个组别属于哪个项目,然后取消该项目的其他组别
|
||||||
const clickedGroup = allGroups.value.find(g => g.id === id);
|
// const clickedGroup = allGroups.value.find(g => g.id === id);
|
||||||
if (clickedGroup && clickedGroup.projectId) {
|
// if (clickedGroup && clickedGroup.projectId) {
|
||||||
// 移除同一项目下的其他组别
|
// // 移除同一项目下的其他组别
|
||||||
selectedGroupIds.value = selectedGroupIds.value.filter(selectedId => {
|
// selectedGroupIds.value = selectedGroupIds.value.filter(selectedId => {
|
||||||
const selectedGroup = allGroups.value.find(g => g.id === selectedId);
|
// const selectedGroup = allGroups.value.find(g => g.id === selectedId);
|
||||||
return selectedGroup?.projectId !== clickedGroup.projectId;
|
// return selectedGroup?.projectId !== clickedGroup.projectId;
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
// 添加新选中的组别
|
// 添加新选中的组别
|
||||||
selectedGroupIds.value.push(id);
|
selectedGroupIds.value.push(id);
|
||||||
}
|
}
|
||||||
@ -1475,6 +1511,8 @@ const openRegistrationDialog = async (row) => {
|
|||||||
paymentMethod.value = 1;
|
paymentMethod.value = 1;
|
||||||
isShowRegisterDialog.value = true;
|
isShowRegisterDialog.value = true;
|
||||||
activeStep.value = 0;
|
activeStep.value = 0;
|
||||||
|
// 加载团队列表(第一步需要展示)
|
||||||
|
fetchTeamList();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('打开报名弹窗失败:', error);
|
console.error('打开报名弹窗失败:', error);
|
||||||
ElMessage.error('项目加载失败');
|
ElMessage.error('项目加载失败');
|
||||||
@ -1531,7 +1569,8 @@ const onTeamChange = async (teamId) => {
|
|||||||
mobile: m.mobile ?? '',
|
mobile: m.mobile ?? '',
|
||||||
gender: m.gender ?? '',
|
gender: m.gender ?? '',
|
||||||
role: m.role ?? '',
|
role: m.role ?? '',
|
||||||
teamId: teamId, // 添加团队ID
|
birthDate: m.birthDate ?? m.birthday ?? '',
|
||||||
|
teamId: teamId,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
@ -1590,7 +1629,7 @@ const validateMemberForGroup = async (member, group) => {
|
|||||||
|
|
||||||
// 实时验证所有已选择的队员
|
// 实时验证所有已选择的队员
|
||||||
const validateAllMembers = async () => {
|
const validateAllMembers = async () => {
|
||||||
if (!currentEventId.value || activeStep.value !== 1) {
|
if (!currentEventId.value || activeStep.value !== 2) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2050,16 +2089,21 @@ const fetchMembers = async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handlePrevious = () => {
|
const handlePrevious = () => {
|
||||||
if (activeStep.value === 2) {
|
if (activeStep.value === 3) {
|
||||||
activeStep.value = 1;
|
activeStep.value = 2;
|
||||||
previewData.value = null;
|
previewData.value = null;
|
||||||
previewLoading.value = false;
|
previewLoading.value = false;
|
||||||
draftRegistrationId.value = null;
|
draftRegistrationId.value = null;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (activeStep.value === 2) {
|
||||||
|
activeStep.value = 1;
|
||||||
|
resetAssignMembersAndBeyond();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (activeStep.value === 1) {
|
if (activeStep.value === 1) {
|
||||||
activeStep.value = 0;
|
activeStep.value = 0;
|
||||||
resetStep2AndBeyond();
|
selectedGroupIds.value = [];
|
||||||
return;
|
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 () => {
|
const handleStep1Next = async () => {
|
||||||
if (!(selectedGroupIds.value?.length ?? 0)) {
|
if (!(selectedGroupIds.value?.length ?? 0)) {
|
||||||
ElMessage.warning('请先选择报名组别');
|
ElMessage.warning('请先选择报名组别');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
activeStep.value = 1;
|
activeStep.value = 2;
|
||||||
resetStep2AndBeyond();
|
resetAssignMembersAndBeyond();
|
||||||
// 默认激活第一个组别
|
// 默认激活第一个组别
|
||||||
if (selectedGroupItems.value.length > 0) {
|
if (selectedGroupItems.value.length > 0) {
|
||||||
activeAssignGroupId.value = selectedGroupItems.value[0].id;
|
activeAssignGroupId.value = selectedGroupItems.value[0].id;
|
||||||
}
|
}
|
||||||
// 加载团队列表
|
// 团队已在第一步选择,无需再次加载团队列表
|
||||||
await fetchTeamList();
|
|
||||||
// 加载队伍限制配置
|
// 加载队伍限制配置
|
||||||
await fetchGroupTeamLimit();
|
await fetchGroupTeamLimit();
|
||||||
|
|
||||||
@ -2334,7 +2400,7 @@ const handleStep2Next = async () => {
|
|||||||
}
|
}
|
||||||
draftRegistrationId.value = data;
|
draftRegistrationId.value = data;
|
||||||
|
|
||||||
activeStep.value = 2;
|
activeStep.value = 3;
|
||||||
previewLoading.value = true;
|
previewLoading.value = true;
|
||||||
try {
|
try {
|
||||||
const { succeeded: pOk, data: pData } = await usereventregistrationPreviewGet(data);
|
const { succeeded: pOk, data: pData } = await usereventregistrationPreviewGet(data);
|
||||||
@ -4006,4 +4072,74 @@ const handleCreateOrderAndPay = async () => {
|
|||||||
text-align: center;
|
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>
|
</style>
|
||||||
Loading…
x
Reference in New Issue
Block a user