This commit is contained in:
马梓彭 2026-04-17 12:48:38 +08:00
commit 4e851c9e36

View File

@ -3,15 +3,8 @@
<ProTable ref="tableRef" :request-api="usereventregistrationListGet" :columns="columns" :pagination="true" <ProTable ref="tableRef" :request-api="usereventregistrationListGet" :columns="columns" :pagination="true"
:tool-button="false" :init-param="initParam" row-key="id"> :tool-button="false" :init-param="initParam" row-key="id">
<template #coverImage="scope"> <template #coverImage="scope">
<PreviewImage <PreviewImage v-if="scope.row?.coverImage" :src="scope.row.coverImage" width="80px" height="60px"
v-if="scope.row?.coverImage" fit="cover" radius="4px" :show-zoom-icon="true" />
:src="scope.row.coverImage"
width="80px"
height="60px"
fit="cover"
radius="4px"
:show-zoom-icon="true"
/>
<span v-else>-</span> <span v-else>-</span>
</template> </template>
@ -61,7 +54,8 @@
</ProTable> </ProTable>
<!-- 赛事详情弹窗 --> <!-- 赛事详情弹窗 -->
<el-dialog title="赛事详情" v-model="isShowDetailDialog" width="80%" style="min-height: 600px;" @closed="clearDetailState"> <el-dialog title="赛事详情" v-model="isShowDetailDialog" width="80%" style="min-height: 600px;"
@closed="clearDetailState">
<el-skeleton :rows="12" animated v-if="detailLoading" /> <el-skeleton :rows="12" animated v-if="detailLoading" />
<template v-else> <template v-else>
<div v-if="formData"> <div v-if="formData">
@ -103,22 +97,21 @@
<div class="project-card" v-for="project in projects" :key="project.id"> <div class="project-card" v-for="project in projects" :key="project.id">
<div class="project-card-left"> <div class="project-card-left">
<div class="project-card-name">名称:{{ project.name }}</div> <div class="project-card-name">名称:{{ project.name }}</div>
<div class="project-card-type">类型:{{ project.parentProjectTypeName ?? project.projectTypeName ?? '' }}</div> <div class="project-card-type">类型:{{ project.parentProjectTypeName ??
project.projectTypeName ?? '' }}</div>
<div class="project-card-count">完成人数:{{ project.completionCount ?? 0 }}</div> <div class="project-card-count">完成人数:{{ project.completionCount ?? 0 }}</div>
</div> </div>
<div class="project-card-right"> <div class="project-card-right">
<div <div v-for="g in (project.groups ?? [])" :key="g.id" class="group-tag"
v-for="g in (project.groups ?? [])"
:key="g.id"
class="group-tag"
:class="{ 'group-tag-selected': selectedGroupIds.includes(g.id) }" :class="{ 'group-tag-selected': selectedGroupIds.includes(g.id) }"
@click="toggleGroupSelection(g.id)" @click="toggleGroupSelection(g.id)">
>
<span class="group-tag-name">{{ g.groupName ?? g.name }}</span> <span class="group-tag-name">{{ g.groupName ?? g.name }}</span>
<span class="group-tag-date" v-if="g.birthDateStart || g.birthDateEnd">{{ formatGroupDate(g) }}</span> <span class="group-tag-date" v-if="g.birthDateStart || g.birthDateEnd">{{
formatGroupDate(g) }}</span>
<span class="group-tag-gender">{{ formatGender(g.gender) }}</span> <span class="group-tag-gender">{{ formatGender(g.gender) }}</span>
</div> </div>
<el-empty v-if="!(project.groups?.length)" description="暂无组别" :image-size="40" style="padding: 8px 0;" /> <el-empty v-if="!(project.groups?.length)" description="暂无组别" :image-size="40"
style="padding: 8px 0;" />
</div> </div>
</div> </div>
@ -126,14 +119,8 @@
<div class="selected-summary" v-if="selectedGroupItems.length > 0"> <div class="selected-summary" v-if="selectedGroupItems.length > 0">
<div class="selected-summary-header">报名项目</div> <div class="selected-summary-header">报名项目</div>
<div class="selected-summary-list"> <div class="selected-summary-list">
<el-tag <el-tag v-for="item in selectedGroupItems" :key="item.id" closable
v-for="item in selectedGroupItems" @close="toggleGroupSelection(item.id)" style="margin: 4px;" size="large">
:key="item.id"
closable
@close="toggleGroupSelection(item.id)"
style="margin: 4px;"
size="large"
>
{{ item.groupName ?? item.name }} {{ item.groupName ?? item.name }}
<template v-if="item.dateRange"> · {{ item.dateRange }}</template> <template v-if="item.dateRange"> · {{ item.dateRange }}</template>
· {{ formatGender(item.gender) }} · {{ formatGender(item.gender) }}
@ -144,11 +131,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 <el-button type="primary" @click="handleStep1Next" :loading="registerLoading">
type="primary"
@click="handleStep1Next"
:loading="registerLoading"
>
下一步 下一步
</el-button> </el-button>
</div> </div>
@ -160,101 +143,84 @@
<div class="step2-layout"> <div class="step2-layout">
<!-- 左侧:已选组别,每个组别可分配队员 --> <!-- 左侧:已选组别,每个组别可分配队员 -->
<div class="step2-left"> <div class="step2-left">
<div <div class="assign-card" v-for="(group, gIdx) in selectedGroupItems" :key="group.id"
class="assign-card"
v-for="(group, gIdx) in selectedGroupItems"
:key="group.id"
:class="{ 'assign-card-active': activeAssignGroupId === group.id }" :class="{ 'assign-card-active': activeAssignGroupId === group.id }"
@click="activeAssignGroupId = group.id" @click="activeAssignGroupId = group.id">
>
<div class="assign-card-header"> <div class="assign-card-header">
<span> <span>
({{ group.parentProjectTypeName ?? group.projectTypeName ?? (group.projectTeamSize > 1 ? '团队' : '个人') }}/{{ group.projectCompletionCount ?? 0 }}) ({{ group.parentProjectTypeName ?? group.projectTypeName ??
{{ group.projectName }}-{{ group.groupName ?? group.name }}/{{ formatGroupDate(group) }}/{{ formatGender(group.gender) }} (group.projectTeamSize > 1 ?
'团队' : '个人') }}/{{ group.projectCompletionCount ?? 0 }})
{{ group.projectName }}-{{ group.groupName ?? group.name }}/{{
formatGroupDate(group) }}/{{
formatGender(group.gender) }}
</span> </span>
<el-icon class="assign-card-close" @click.stop="toggleGroupSelection(group.id)"><Close /></el-icon> <el-icon class="assign-card-close" @click.stop="toggleGroupSelection(group.id)">
<Close />
</el-icon>
</div> </div>
<!-- 团队数量信息和添加团队按钮 --> <!-- 团队数量信息和添加团队按钮 -->
<div class="team-info-section" v-if="isTeamProject(group) && getGroupMaxTeams(group.id) > 1"> <div class="team-info-section"
v-if="isTeamProject(group) && getGroupMaxTeams(group.id) > 1">
<div class="team-count-info"> <div class="team-count-info">
已添加 {{ getGroupTeams(group.id).length }} / {{ getGroupMaxTeams(group.id) }} 队 已添加 {{ getGroupTeams(group.id).length }} / {{ getGroupMaxTeams(group.id) }} 队
</div> </div>
<el-button <el-button v-if="getGroupTeams(group.id).length < getGroupMaxTeams(group.id)"
v-if="getGroupTeams(group.id).length < getGroupMaxTeams(group.id)" type="primary" size="small" text @click.stop="addTeam(group.id)">
type="primary" <el-icon>
size="small" <Plus />
text </el-icon>
@click.stop="addTeam(group.id)"
>
<el-icon><Plus /></el-icon>
添加团队 添加团队
</el-button> </el-button>
</div> </div>
<!-- 团队列表 --> <!-- 团队列表 -->
<div v-if="isTeamProject(group) && getGroupMaxTeams(group.id) > 1" class="team-section"> <div v-if="isTeamProject(group) && getGroupMaxTeams(group.id) > 1" class="team-section">
<div <div v-for="team in getGroupTeams(group.id)" :key="team.teamIndex" class="team-card"
v-for="team in getGroupTeams(group.id)"
:key="team.teamIndex"
class="team-card"
:class="{ 'team-card-active': activeTeamKey === `${group.id}_${team.teamIndex}` }" :class="{ 'team-card-active': activeTeamKey === `${group.id}_${team.teamIndex}` }"
@click.stop="setActiveTeam(group.id, team.teamIndex)" :data-team-key="`${group.id}_${team.teamIndex}`"
> @click.stop="setActiveTeam(group.id, team.teamIndex)">
<div class="team-card-header"> <div class="team-card-header">
<span class="team-name">团队{{ getTeamNumber(team.teamIndex) }}</span> <span class="team-name">团队{{ getTeamNumber(team.teamIndex) }}</span>
<el-button <el-button v-if="getGroupTeams(group.id).length > 1" type="danger"
v-if="getGroupTeams(group.id).length > 1" size="small" text @click.stop="removeTeam(group.id, team.teamIndex)">
type="danger" <el-icon>
size="small" <Delete />
text </el-icon>
@click.stop="removeTeam(group.id, team.teamIndex)"
>
<el-icon><Delete /></el-icon>
</el-button> </el-button>
</div> </div>
<div class="team-members"> <div class="team-members">
<el-tag <el-tag v-for="m in team.members" :key="m.userId ?? m.id" closable
v-for="m in team.members"
:key="m.userId ?? m.id"
closable
:type="getMemberValidationResult(m, group).isValid ? '' : 'danger'" :type="getMemberValidationResult(m, group).isValid ? '' : 'danger'"
@close.stop="removeMemberFromTeam(group.id, team.teamIndex, m.userId ?? m.id)" @close.stop="removeMemberFromTeam(group.id, team.teamIndex, m.userId ?? m.id)"
style="margin: 3px;" style="margin: 3px;">
>
{{ m.name }} {{ m.name }}
</el-tag> </el-tag>
<span v-if="!team.members.length" class="team-placeholder">选择此团队后添加队员</span> <span v-if="!team.members.length" class="team-placeholder">选择此团队后添加队员</span>
</div> </div>
</div> </div>
</div> </div>
<!-- 单团队模式(向后兼容) --> <!-- 单团队模式(向后兼容) -->
<div v-else class="assign-card-members"> <div v-else class="assign-card-members">
<el-tag <el-tag v-for="m in (groupMemberMap[group.id] ?? [])" :key="m.userId ?? m.id"
v-for="m in (groupMemberMap[group.id] ?? [])" closable :type="getMemberValidationResult(m, group).isValid ? '' : 'danger'"
:key="m.userId ?? m.id" @close="removeMemberFromGroup(group.id, m.userId ?? m.id)" style="margin: 3px;">
closable
:type="getMemberValidationResult(m, group).isValid ? '' : 'danger'"
@close="removeMemberFromGroup(group.id, m.userId ?? m.id)"
style="margin: 3px;"
>
{{ m.name }} {{ m.name }}
</el-tag> </el-tag>
<span v-if="!(groupMemberMap[group.id]?.length)" class="assign-card-placeholder">点击此卡片后,从右侧选择队员</span> <span v-if="!(groupMemberMap[group.id]?.length)"
class="assign-card-placeholder">点击此卡片后,从右侧选择队员</span>
</div> </div>
<!-- 队员验证错误提示 --> <!-- 队员验证错误提示 -->
<div v-if="hasValidationErrorsForGroup(group)" class="validation-error-section"> <div v-if="hasValidationErrorsForGroup(group)" class="validation-error-section">
<div class="validation-error-item" v-for="m in (isTeamProject(group) && getGroupMaxTeams(group.id) > 1 ? getGroupTeams(group.id).flatMap(t => t.members) : (groupMemberMap[group.id] ?? []))" :key="m.userId ?? m.id"> <div class="validation-error-item"
<el-alert v-for="m in (isTeamProject(group) && getGroupMaxTeams(group.id) > 1 ? getGroupTeams(group.id).flatMap(t => t.members) : (groupMemberMap[group.id] ?? []))"
v-if="!getMemberValidationResult(m, group).isValid" :key="m.userId ?? m.id">
:title="getMemberValidationResult(m, group).message" <el-alert v-if="!getMemberValidationResult(m, group).isValid"
type="error" :title="getMemberValidationResult(m, group).message" type="error"
:closable="false" :closable="false" size="small" style="margin-top: 4px;" />
size="small"
style="margin-top: 4px;"
/>
</div> </div>
</div> </div>
</div> </div>
@ -264,33 +230,19 @@
<!-- 右侧:团队选择器 + 成员列表 --> <!-- 右侧:团队选择器 + 成员列表 -->
<div class="step2-right"> <div class="step2-right">
<div class="team-selector"> <div class="team-selector">
<el-select <el-select v-model="selectedTeamId" placeholder="请选择团队" style="width: 100%;"
v-model="selectedTeamId" @change="onTeamChange" :loading="teamListLoading" filterable>
placeholder="请选择团队" <el-option v-for="t in teamList" :key="t.id" :label="t.name" :value="t.id" />
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> </el-select>
</div> </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" :description="selectedTeamId ? '该团队暂无运动员' : '请先选择团队'" :image-size="60" /> <el-empty v-else-if="!teamMembers.length"
:description="selectedTeamId ? '该团队暂无运动员' : '请先选择团队'" :image-size="60" />
<template v-else> <template v-else>
<div <div v-for="m in teamMembers" :key="m.userId ?? m.id" class="team-member-tag"
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) }"
@click="assignMemberToActiveTeam(m)" @click="assignMemberToActiveTeam(m)">
>
{{ m.name }} {{ m.name }}
</div> </div>
</template> </template>
@ -301,48 +253,29 @@
<!-- 验证提示区域 --> <!-- 验证提示区域 -->
<div class="validation-notes-section"> <div class="validation-notes-section">
<!-- 年龄性别不符合要求提示 --> <!-- 年龄性别不符合要求提示 -->
<el-alert <el-alert v-if="hasAnyValidationErrors()" title="队员信息不符合组别要求" type="error" :closable="false"
v-if="hasAnyValidationErrors()" style="margin-bottom: 12px;" />
title="队员信息不符合组别要求"
type="error"
:closable="false"
style="margin-bottom: 12px;"
/>
<!-- 限报提示 --> <!-- 限报提示 -->
<template v-if="hasAnyRegistrationLimit()"> <template v-if="hasAnyRegistrationLimit()">
<el-alert <el-alert v-for="(detail, index) in (registrationLimitCheckResult?.limitDetails ?? [])"
v-for="(detail, index) in (registrationLimitCheckResult?.limitDetails ?? [])" :key="index" :title="detail?.limitMessage ?? '报名限制'" type="warning" :closable="false"
:key="index" style="margin-bottom: 12px;" />
:title="detail?.limitMessage ?? '报名限制'"
type="warning"
:closable="false"
style="margin-bottom: 12px;"
/>
</template> </template>
<!-- 队伍数量限制提示 --> <!-- 队伍数量限制提示 -->
<el-alert <el-alert v-if="showTeamLimitHint" title="若管理后台配置一个组别只能限报2队,添加2队后,'添加'按钮隐藏" type="info"
v-if="showTeamLimitHint" :closable="false" style="margin-bottom: 12px;" />
title="若管理后台配置一个组别只能限报2队,添加2队后,'添加'按钮隐藏"
type="info"
:closable="false"
style="margin-bottom: 12px;"
/>
</div> </div>
<!-- 底部操作区域 --> <!-- 底部操作区域 -->
<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 @click="handlePrevious" style="margin-right: 10px;">上一步</el-button>
<el-button <el-button type="primary" @click="handleStep2Next" :loading="submitDraftLoading"
type="primary" :disabled="hasAnyValidationErrors() || hasAnyRegistrationLimit()">
@click="handleStep2Next"
:loading="submitDraftLoading"
:disabled="hasAnyValidationErrors() || hasAnyRegistrationLimit()"
>
下一步 下一步
</el-button> </el-button>
</div> </div>
@ -378,13 +311,15 @@
</div> </div>
<!-- 支付二维码显示区域(微信/支付宝) --> <!-- 支付二维码显示区域(微信/支付宝) -->
<div v-else-if="paymentData" class="payment-qrcode-section"> <div v-else-if="paymentData" class="payment-qrcode-section">
<div class="qrcode-title">请使用{{ paymentMethod === 2 ? '支付宝' : '微信'}}扫码支付</div> <div class="qrcode-title">请使用{{ paymentMethod === 2 ? '支付宝' : '微信' }}扫码支付</div>
<div class="qrcode-wrapper"> <div class="qrcode-wrapper">
<div v-if="paymentData.qrcodeUrl" class="qrcode-container"> <div v-if="paymentData.qrcodeUrl" class="qrcode-container">
<div ref="qrcodeRef"></div> <div ref="qrcodeRef"></div>
</div> </div>
<div v-else class="qrcode-placeholder"> <div v-else class="qrcode-placeholder">
<el-icon :size="60" color="#909399"><Picture /></el-icon> <el-icon :size="60" color="#909399">
<Picture />
</el-icon>
<div class="qrcode-tip">支付链接获取失败</div> <div class="qrcode-tip">支付链接获取失败</div>
</div> </div>
</div> </div>
@ -393,7 +328,9 @@
<span class="amount-value">¥ {{ finalPaymentAmount }}</span> <span class="amount-value">¥ {{ finalPaymentAmount }}</span>
</div> </div>
<div class="payment-status" v-if="pollingStatus"> <div class="payment-status" v-if="pollingStatus">
<el-icon class="is-loading"><Loading /></el-icon> <el-icon class="is-loading">
<Loading />
</el-icon>
{{ pollingStatus }} {{ pollingStatus }}
</div> </div>
</div> </div>
@ -408,7 +345,8 @@
<el-table-column prop="projectTypeName" label="类型" align="center" width="180" /> <el-table-column prop="projectTypeName" label="类型" align="center" width="180" />
<el-table-column label="参赛队员" align="center" min-width="200"> <el-table-column label="参赛队员" align="center" min-width="200">
<template #default="scope"> <template #default="scope">
<el-tag size="small" style="margin: 2px;" v-for="member in scope.row?.members" :key="member.userId"> <el-tag size="small" style="margin: 2px;" v-for="member in scope.row?.members"
:key="member.userId">
{{ member.name }} {{ member.name }}
</el-tag> </el-tag>
</template> </template>
@ -419,32 +357,23 @@
<div class="coupon-section"> <div class="coupon-section">
<div class="detail-section-title">优惠券</div> <div class="detail-section-title">优惠券</div>
<div class="coupon-input-wrapper"> <div class="coupon-input-wrapper">
<el-input <el-input v-model="couponCode" placeholder="请输入优惠券兑换码" :disabled="!!validatedCoupon"
v-model="couponCode" style="flex: 1; margin-right: 10px;" clearable />
placeholder="请输入优惠券兑换码" <el-button v-if="!validatedCoupon" type="primary" :loading="couponValidationLoading"
:disabled="!!validatedCoupon" @click="validateCoupon">
style="flex: 1; margin-right: 10px;"
clearable
/>
<el-button
v-if="!validatedCoupon"
type="primary"
:loading="couponValidationLoading"
@click="validateCoupon"
>
使用优惠券 使用优惠券
</el-button> </el-button>
<el-button <el-button v-else type="danger" @click="clearCoupon">
v-else
type="danger"
@click="clearCoupon"
>
清除优惠券 清除优惠券
</el-button> </el-button>
</div> </div>
<div v-if="validatedCoupon" class="coupon-result success"> <div v-if="validatedCoupon" class="coupon-result success">
<el-icon style="color: #67c23a;"><CircleCheck /></el-icon> <el-icon style="color: #67c23a;">
<span>{{ validatedCoupon.couponName }},{{validatedCoupon.discountType == 0 ? `优惠价${validatedCoupon.discountValue / 10}折` : `优惠 ${validatedCoupon.discountAmount}元`}}</span> <CircleCheck />
</el-icon>
<span>{{ validatedCoupon.couponName }},{{ validatedCoupon.discountType == 0 ?
`优惠价${validatedCoupon.discountValue / 10}折` : `优惠
${validatedCoupon.discountAmount}元`}}</span>
</div> </div>
</div> </div>
@ -462,16 +391,19 @@
</div> </div>
<div class="payment-actions"> <div class="payment-actions">
<div class="payment-method-wrapper" v-if="!isFreePreview"> <div class="payment-method-wrapper" v-if="!isFreePreview">
<el-select v-model="paymentMethod" placeholder="请选择支付方式" style="width: 200px; margin-right: 10px;"> <el-select v-model="paymentMethod" placeholder="请选择支付方式"
style="width: 200px; margin-right: 10px;">
<el-option :value="1" label="微信支付" /> <el-option :value="1" label="微信支付" />
<el-option :value="2" label="支付宝支付" /> <el-option :value="2" label="支付宝支付" />
<el-option :value="3" label="银行转账" /> <el-option :value="3" label="银行转账" />
</el-select> </el-select>
<el-button type="primary" @click="handleCreateOrderAndPay" :loading="createOrderLoading" :disabled="!draftRegistrationId"> <el-button type="primary" @click="handleCreateOrderAndPay"
:loading="createOrderLoading" :disabled="!draftRegistrationId">
确认支付 确认支付
</el-button> </el-button>
</div> </div>
<el-button v-else type="primary" @click="handleCreateOrderAndPay" :loading="createOrderLoading" :disabled="!draftRegistrationId"> <el-button v-else type="primary" @click="handleCreateOrderAndPay"
:loading="createOrderLoading" :disabled="!draftRegistrationId">
确认报名 确认报名
</el-button> </el-button>
</div> </div>
@ -488,8 +420,10 @@
<!-- 底部操作区域 --> <!-- 底部操作区域 -->
<div class="step-footer step-footer--payment"> <div class="step-footer step-footer--payment">
<el-button @click="isShowRegisterDialog = false">取消</el-button> <el-button @click="isShowRegisterDialog = false">取消</el-button>
<el-button v-if="paymentData" type="primary" @click="refreshPayment" :loading="polling">刷新二维码</el-button> <el-button v-if="paymentData" type="primary" @click="refreshPayment"
<el-button v-if="paymentData && paymentMethod === 3" type="primary" @click="confirmBankTransfer">确认已转账</el-button> :loading="polling">刷新二维码</el-button>
<el-button v-if="paymentData && paymentMethod === 3" type="primary"
@click="confirmBankTransfer">确认已转账</el-button>
<el-button @click="handlePrevious">上一步</el-button> <el-button @click="handlePrevious">上一步</el-button>
</div> </div>
</div> </div>
@ -543,13 +477,15 @@ const columns = ref([
{ prop: 'type', label: '赛事类型', align: 'center', width: 120 }, { prop: 'type', label: '赛事类型', align: 'center', width: 120 },
{ prop: 'registrationType', label: '报名方式', align: 'center', width: 120 }, { prop: 'registrationType', label: '报名方式', align: 'center', width: 120 },
{ prop: 'chargeMode', label: '收费模式', align: 'center', width: 120 }, { prop: 'chargeMode', label: '收费模式', align: 'center', width: 120 },
{ prop: 'status', label: '赛事状态', align: 'center', width: 120 , enum: [ {
prop: 'status', label: '赛事状态', align: 'center', width: 120, enum: [
{ label: '未开始', value: 0 }, { label: '未开始', value: 0 },
{ label: '报名中', value: 1 }, { label: '报名中', value: 1 },
{ label: '报名结束', value: 2 }, { label: '报名结束', value: 2 },
{ label: '比赛中', value: 3 }, { label: '比赛中', value: 3 },
{ label: '已结束', value: 4 }, { label: '已结束', value: 4 },
],}, ],
},
{ prop: 'registrationStartTime', label: '报名起止时间', align: 'center', minWidth: 320 }, { prop: 'registrationStartTime', label: '报名起止时间', align: 'center', minWidth: 320 },
{ prop: 'matchStartTime', label: '比赛起止时间', align: 'center', minWidth: 320 }, { prop: 'matchStartTime', label: '比赛起止时间', align: 'center', minWidth: 320 },
{ prop: 'action', label: '操作', align: 'center', fixed: 'right', width: 210 }, { prop: 'action', label: '操作', align: 'center', fixed: 'right', width: 210 },
@ -905,8 +841,8 @@ const formatGender = (gender) => {
if (v === 0) return '男'; if (v === 0) return '男';
if (v === 1) return '女'; if (v === 1) return '女';
if (v === 2) return '保密'; if (v === 2) return '保密';
if (v === 3) return '不限'; if (v === 3) return '性别不限';
return '不限'; return '性别不限';
}; };
// 格式化组别的年龄段(出生日期范围) // 格式化组别的年龄段(出生日期范围)
@ -1066,7 +1002,7 @@ const openRegistrationDialog = async (row) => {
ElMessage.error(data ?? '项目加载失败'); ElMessage.error(data ?? '项目加载失败');
return; return;
} }
// 检查报名类型,如果是只允许个人报名,则显示提示并阻止继续 // 检查报名类型,如果是只允许个人报名,则显示提示并阻止继续
const registrationType = data?.registrationType; const registrationType = data?.registrationType;
if (registrationType === 'OnlyIndividual') { if (registrationType === 'OnlyIndividual') {
@ -1080,7 +1016,7 @@ const openRegistrationDialog = async (row) => {
); );
return; return;
} }
// 保存完整的详情数据,用于项目类型显示等 // 保存完整的详情数据,用于项目类型显示等
detailData.value = data; detailData.value = data;
projects.value = Array.isArray(data?.projects) ? data.projects : []; projects.value = Array.isArray(data?.projects) ? data.projects : [];
@ -1119,7 +1055,7 @@ const fetchTeamList = async () => {
const onTeamChange = async (teamId) => { const onTeamChange = async (teamId) => {
teamMembers.value = []; teamMembers.value = [];
if (!teamId) return; if (!teamId) return;
// 检查是否已经分配了其他团队的队员 // 检查是否已经分配了其他团队的队员
if (usedTeamId.value && usedTeamId.value !== teamId) { if (usedTeamId.value && usedTeamId.value !== teamId) {
ElMessage.warning('本次报名已选择了其他团队的队员,请先移除已分配的队员'); ElMessage.warning('本次报名已选择了其他团队的队员,请先移除已分配的队员');
@ -1127,7 +1063,7 @@ const onTeamChange = async (teamId) => {
selectedTeamId.value = usedTeamId.value; selectedTeamId.value = usedTeamId.value;
return; return;
} }
teamMemberLoading.value = true; teamMemberLoading.value = true;
try { try {
const { succeeded, data } = await teamDetailGet(teamId); const { succeeded, data } = await teamDetailGet(teamId);
@ -1154,7 +1090,20 @@ const onTeamChange = async (teamId) => {
// 判断某成员是否已分配到当前激活的组别 // 判断某成员是否已分配到当前激活的组别
const isMemberAssignedToActive = (memberId) => { const isMemberAssignedToActive = (memberId) => {
if (!activeAssignGroupId.value) return false; if (!activeAssignGroupId.value) return false;
const list = groupMemberMap.value[activeAssignGroupId.value] ?? []; const gId = activeAssignGroupId.value;
// 多团队模式:检查当前激活的 team-card 里是否有该成员
if (activeTeamKey.value) {
const [activeGroupId, activeTeamIdx] = activeTeamKey.value.split('_').map(Number);
if (activeGroupId === gId) {
const teams = groupTeamsMap.value[gId] ?? [];
const team = teams.find(t => t.teamIndex === activeTeamIdx);
if (team) {
return team.members.some(m => (m.userId ?? m.id) === memberId);
}
}
}
// 单团队模式降级
const list = groupMemberMap.value[gId] ?? [];
return list.some((m) => (m.userId ?? m.id) === memberId); return list.some((m) => (m.userId ?? m.id) === memberId);
}; };
@ -1200,13 +1149,13 @@ const validateAllMembers = async () => {
for (const group of selectedGroupItems.value) { for (const group of selectedGroupItems.value) {
const gId = group.id; const gId = group.id;
// 检查是否为团队项目且启用了多团队模式 // 检查是否为团队项目且启用了多团队模式
const isMultiTeamMode = isTeamProject(group) && groupTeamsMap.value[gId] && const isMultiTeamMode = isTeamProject(group) && groupTeamsMap.value[gId] &&
(groupTeamsMap.value[gId].length > 1 || getGroupMaxTeams(gId) > 1); (groupTeamsMap.value[gId].length > 1 || getGroupMaxTeams(gId) > 1);
let membersToValidate = []; let membersToValidate = [];
if (isMultiTeamMode) { if (isMultiTeamMode) {
// 多团队模式:收集所有团队的队员 // 多团队模式:收集所有团队的队员
for (const team of groupTeamsMap.value[gId]) { for (const team of groupTeamsMap.value[gId]) {
@ -1330,7 +1279,7 @@ const assignMemberToActiveGroup = async (member) => {
const removeMemberFromGroup = (groupId, memberId) => { const removeMemberFromGroup = (groupId, memberId) => {
if (!groupMemberMap.value[groupId]) return; if (!groupMemberMap.value[groupId]) return;
groupMemberMap.value[groupId] = groupMemberMap.value[groupId].filter((m) => (m.userId ?? m.id) !== memberId); groupMemberMap.value[groupId] = groupMemberMap.value[groupId].filter((m) => (m.userId ?? m.id) !== memberId);
// 检查是否还有队员,如果没有则重置已使用的团队 // 检查是否还有队员,如果没有则重置已使用的团队
let hasMembers = false; let hasMembers = false;
Object.values(groupMemberMap.value).forEach(members => { Object.values(groupMemberMap.value).forEach(members => {
@ -1341,7 +1290,7 @@ const removeMemberFromGroup = (groupId, memberId) => {
if (!hasMembers) { if (!hasMembers) {
usedTeamId.value = null; usedTeamId.value = null;
} }
// 触发实时验证 // 触发实时验证
debounceValidateAllMembers(); debounceValidateAllMembers();
}; };
@ -1364,18 +1313,18 @@ const isTeamProject = (group) => {
// 1006: 团队花样 // 1006: 团队花样
return group.projectType === 1005 || group.projectType === 1006; return group.projectType === 1005 || group.projectType === 1006;
} }
// 备用判断:使用 projectTypeName 或 parentProjectTypeName // 备用判断:使用 projectTypeName 或 parentProjectTypeName
if (group?.projectTypeName || group?.parentProjectTypeName) { if (group?.projectTypeName || group?.parentProjectTypeName) {
const typeName = group.projectTypeName || group.parentProjectTypeName; const typeName = group.projectTypeName || group.parentProjectTypeName;
return typeName && typeName.includes('团队'); return typeName && typeName.includes('团队');
} }
// 最后的备用判断:使用 projectTeamSize // 最后的备用判断:使用 projectTeamSize
if (group?.projectTeamSize) { if (group?.projectTeamSize) {
return group.projectTeamSize > 1; return group.projectTeamSize > 1;
} }
return false; return false;
}; };
@ -1407,18 +1356,18 @@ const addTeam = (groupId) => {
initGroupTeams(groupId); initGroupTeams(groupId);
const teams = groupTeamsMap.value[groupId]; const teams = groupTeamsMap.value[groupId];
const maxTeams = getGroupMaxTeams(groupId); const maxTeams = getGroupMaxTeams(groupId);
if (teams.length >= maxTeams) { if (teams.length >= maxTeams) {
ElMessage.warning(`已达到该项目组别限报${maxTeams}队的上限`); ElMessage.warning(`已达到该项目组别限报${maxTeams}队的上限`);
return; return;
} }
const newTeamIndex = teams.length + 1; const newTeamIndex = teams.length + 1;
teams.push({ teams.push({
teamIndex: newTeamIndex, teamIndex: newTeamIndex,
members: [] members: []
}); });
ElMessage.success(`已添加团队${getTeamNumber(newTeamIndex)}`); ElMessage.success(`已添加团队${getTeamNumber(newTeamIndex)}`);
}; };
@ -1426,12 +1375,12 @@ const addTeam = (groupId) => {
const removeTeam = async (groupId, teamIndex) => { const removeTeam = async (groupId, teamIndex) => {
initGroupTeams(groupId); initGroupTeams(groupId);
const teams = groupTeamsMap.value[groupId]; const teams = groupTeamsMap.value[groupId];
if (teams.length <= 1) { if (teams.length <= 1) {
ElMessage.warning('至少需要保留一个团队'); ElMessage.warning('至少需要保留一个团队');
return; return;
} }
try { try {
await ElMessageBox.confirm( await ElMessageBox.confirm(
`确定要删除团队${getTeamNumber(teamIndex)}吗?该团队的队员也会被移除。`, `确定要删除团队${getTeamNumber(teamIndex)}吗?该团队的队员也会被移除。`,
@ -1442,16 +1391,16 @@ const removeTeam = async (groupId, teamIndex) => {
type: 'warning' type: 'warning'
} }
); );
const teamIdx = teams.findIndex(t => t.teamIndex === teamIndex); const teamIdx = teams.findIndex(t => t.teamIndex === teamIndex);
if (teamIdx > -1) { if (teamIdx > -1) {
teams.splice(teamIdx, 1); teams.splice(teamIdx, 1);
// 重新编号团队索引 // 重新编号团队索引
teams.forEach((team, idx) => { teams.forEach((team, idx) => {
team.teamIndex = idx + 1; team.teamIndex = idx + 1;
}); });
ElMessage.success('团队删除成功'); ElMessage.success('团队删除成功');
} }
} catch { } catch {
@ -1465,24 +1414,29 @@ const getActiveTeamMembers = (groupId) => {
if (!groupTeamsMap.value[groupId] || groupTeamsMap.value[groupId].length === 0) { if (!groupTeamsMap.value[groupId] || groupTeamsMap.value[groupId].length === 0) {
return groupMemberMap.value[groupId] ?? []; return groupMemberMap.value[groupId] ?? [];
} }
// 多团队模式:找到当前激活的团队 // 多团队模式:找到当前激活的团队
if (!activeTeamKey.value) { if (!activeTeamKey.value) {
return []; return [];
} }
const [activeGroupId, activeTeamIdx] = activeTeamKey.value.split('_').map(Number); const [activeGroupId, activeTeamIdx] = activeTeamKey.value.split('_').map(Number);
if (activeGroupId !== groupId) { if (activeGroupId !== groupId) {
return []; return [];
} }
const team = groupTeamsMap.value[groupId].find(t => t.teamIndex === activeTeamIdx); const team = groupTeamsMap.value[groupId].find(t => t.teamIndex === activeTeamIdx);
return team?.members ?? []; return team?.members ?? [];
}; };
// 设置当前激活的团队 // 设置当前激活的团队
const setActiveTeam = (groupId, teamIndex) => { const setActiveTeam = (groupId, teamIndex) => {
activeAssignGroupId.value = groupId;
activeTeamKey.value = `${groupId}_${teamIndex}`; activeTeamKey.value = `${groupId}_${teamIndex}`;
nextTick(() => {
const el = document.querySelector(`.team-card[data-team-key="${groupId}_${teamIndex}"]`);
if (el) el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
});
}; };
// 将成员分配到当前激活的团队 // 将成员分配到当前激活的团队
@ -1492,55 +1446,55 @@ const assignMemberToActiveTeam = async (member) => {
ElMessage.warning('请先点击左侧的组别卡片'); ElMessage.warning('请先点击左侧的组别卡片');
return; return;
} }
initGroupTeams(gId); initGroupTeams(gId);
// 获取当前组别信息 // 获取当前组别信息
const group = selectedGroupItems.value.find(g => g.id === gId); const group = selectedGroupItems.value.find(g => g.id === gId);
// 检查是否为团队项目且启用了多团队模式 // 检查是否为团队项目且启用了多团队模式
const isMultiTeamMode = group && isTeamProject(group) && const isMultiTeamMode = group && isTeamProject(group) &&
(groupTeamsMap.value[gId].length > 1 || getGroupMaxTeams(gId) > 1); (groupTeamsMap.value[gId].length > 1 || getGroupMaxTeams(gId) > 1);
if (!isMultiTeamMode) { if (!isMultiTeamMode) {
// 单团队模式,使用原来的逻辑 // 单团队模式,使用原来的逻辑
await assignMemberToActiveGroup(member); await assignMemberToActiveGroup(member);
return; return;
} }
// 多团队模式 // 多团队模式
if (!activeTeamKey.value) { if (!activeTeamKey.value) {
ElMessage.warning('请先选择要分配队员的团队'); ElMessage.warning('请先选择要分配队员的团队');
return; return;
} }
const [activeGroupId, activeTeamIdx] = activeTeamKey.value.split('_').map(Number); const [activeGroupId, activeTeamIdx] = activeTeamKey.value.split('_').map(Number);
if (activeGroupId !== gId) { if (activeGroupId !== gId) {
ElMessage.warning('请先选择对应组别的团队'); ElMessage.warning('请先选择对应组别的团队');
return; return;
} }
const team = groupTeamsMap.value[gId].find(t => t.teamIndex === activeTeamIdx); const team = groupTeamsMap.value[gId].find(t => t.teamIndex === activeTeamIdx);
if (!team) { if (!team) {
return; return;
} }
const memberId = member.userId ?? member.id; const memberId = member.userId ?? member.id;
// 已存在则不重复添加 // 已存在则不重复添加
if (team.members.some((m) => (m.userId ?? m.id) === memberId)) { if (team.members.some((m) => (m.userId ?? m.id) === memberId)) {
return; return;
} }
// 检查队员是否来自已选择的团队 // 检查队员是否来自已选择的团队
if (usedTeamId.value && member.teamId !== usedTeamId.value) { if (usedTeamId.value && member.teamId !== usedTeamId.value) {
ElMessage.warning('本次报名只能选择同一个团队的队员'); ElMessage.warning('本次报名只能选择同一个团队的队员');
return; return;
} }
// 设置已使用的团队 // 设置已使用的团队
if (!usedTeamId.value) { if (!usedTeamId.value) {
usedTeamId.value = member.teamId; usedTeamId.value = member.teamId;
} }
team.members.push({ ...member, teamId: member.teamId }); team.members.push({ ...member, teamId: member.teamId });
// 触发实时验证(包含报名限制检查) // 触发实时验证(包含报名限制检查)
debounceValidateAllMembers(); debounceValidateAllMembers();
@ -1551,9 +1505,9 @@ const removeMemberFromTeam = (groupId, teamIndex, memberId) => {
initGroupTeams(groupId); initGroupTeams(groupId);
const team = groupTeamsMap.value[groupId].find(t => t.teamIndex === teamIndex); const team = groupTeamsMap.value[groupId].find(t => t.teamIndex === teamIndex);
if (!team) return; if (!team) return;
team.members = team.members.filter((m) => (m.userId ?? m.id) !== memberId); team.members = team.members.filter((m) => (m.userId ?? m.id) !== memberId);
// 检查是否还有队员 // 检查是否还有队员
let hasMembers = false; let hasMembers = false;
groupTeamsMap.value[groupId].forEach(t => { groupTeamsMap.value[groupId].forEach(t => {
@ -1564,7 +1518,7 @@ const removeMemberFromTeam = (groupId, teamIndex, memberId) => {
if (!hasMembers) { if (!hasMembers) {
usedTeamId.value = null; usedTeamId.value = null;
} }
// 触发实时验证 // 触发实时验证
debounceValidateAllMembers(); debounceValidateAllMembers();
}; };
@ -1679,29 +1633,29 @@ const checkRegistrationLimit = async () => {
// 构造按组别分配的数据(与提交报名时保持一致) // 构造按组别分配的数据(与提交报名时保持一致)
const groupMembers = []; const groupMembers = [];
const allMemberIdsSet = new Set(); const allMemberIdsSet = new Set();
for (const gId of selectedGroupIds.value) { for (const gId of selectedGroupIds.value) {
// 找到当前组别信息 // 找到当前组别信息
const group = selectedGroupItems.value.find(g => g.id === gId); const group = selectedGroupItems.value.find(g => g.id === gId);
// 检查是否为团队项目且启用了多团队模式 // 检查是否为团队项目且启用了多团队模式
const isMultiTeamMode = group && isTeamProject(group) && groupTeamsMap.value[gId] && const isMultiTeamMode = group && isTeamProject(group) && groupTeamsMap.value[gId] &&
(groupTeamsMap.value[gId].length > 1 || getGroupMaxTeams(gId) > 1); (groupTeamsMap.value[gId].length > 1 || getGroupMaxTeams(gId) > 1);
if (isMultiTeamMode) { if (isMultiTeamMode) {
// 多团队模式 // 多团队模式
const teams = groupTeamsMap.value[gId]; const teams = groupTeamsMap.value[gId];
const groupTeamsData = []; const groupTeamsData = [];
for (const team of teams) { for (const team of teams) {
const memberIds = team.members.map(m => m.userId ?? m.id); const memberIds = team.members.map(m => m.userId ?? m.id);
memberIds.forEach(id => allMemberIdsSet.add(id)); memberIds.forEach(id => allMemberIdsSet.add(id));
groupTeamsData.push({ groupTeamsData.push({
teamIndex: team.teamIndex, teamIndex: team.teamIndex,
memberIds: memberIds memberIds: memberIds
}); });
} }
groupMembers.push({ groupMembers.push({
groupId: gId, groupId: gId,
memberIds: groupTeamsData.flatMap(t => t.memberIds), // 保持向后兼容 memberIds: groupTeamsData.flatMap(t => t.memberIds), // 保持向后兼容
@ -1711,16 +1665,16 @@ const checkRegistrationLimit = async () => {
// 单团队模式(保持向后兼容) // 单团队模式(保持向后兼容)
const memberIds = (groupMemberMap.value[gId] ?? []).map((m) => m.userId ?? m.id); const memberIds = (groupMemberMap.value[gId] ?? []).map((m) => m.userId ?? m.id);
memberIds.forEach(id => allMemberIdsSet.add(id)); memberIds.forEach(id => allMemberIdsSet.add(id));
groupMembers.push({ groupMembers.push({
groupId: gId, groupId: gId,
memberIds: memberIds memberIds: memberIds
}); });
} }
} }
const allMemberIds = [...allMemberIdsSet]; const allMemberIds = [...allMemberIdsSet];
try { try {
const { succeeded, data } = await usereventregistrationRegistrationLimitCheckPost({ const { succeeded, data } = await usereventregistrationRegistrationLimitCheckPost({
eventId: currentEventId.value, eventId: currentEventId.value,
@ -1783,7 +1737,7 @@ const handleStep1Next = async () => {
await fetchTeamList(); await fetchTeamList();
// 加载队伍限制配置 // 加载队伍限制配置
await fetchGroupTeamLimit(); await fetchGroupTeamLimit();
// 初始化每个组别的团队数据 // 初始化每个组别的团队数据
await nextTick(); await nextTick();
selectedGroupItems.value.forEach(group => { selectedGroupItems.value.forEach(group => {
@ -1813,7 +1767,7 @@ const handleStep2Next = async () => {
for (const g of selectedGroupItems.value) { for (const g of selectedGroupItems.value) {
const gId = g.id; const gId = g.id;
let hasMembers = false; let hasMembers = false;
// 检查是否为团队项目且启用了多团队模式 // 检查是否为团队项目且启用了多团队模式
if (isTeamProject(g) && groupTeamsMap.value[gId] && groupTeamsMap.value[gId].length > 0) { if (isTeamProject(g) && groupTeamsMap.value[gId] && groupTeamsMap.value[gId].length > 0) {
for (const team of groupTeamsMap.value[gId]) { for (const team of groupTeamsMap.value[gId]) {
@ -1826,12 +1780,12 @@ const handleStep2Next = async () => {
// 单团队模式 // 单团队模式
hasMembers = !!(groupMemberMap.value[gId]?.length); hasMembers = !!(groupMemberMap.value[gId]?.length);
} }
if (!hasMembers) { if (!hasMembers) {
emptyGroups.push(g); emptyGroups.push(g);
} }
} }
if (emptyGroups.length > 0) { if (emptyGroups.length > 0) {
ElMessage.warning(`请为所有组别分配队员,"${emptyGroups[0].groupName ?? emptyGroups[0].name}"尚未分配`); ElMessage.warning(`请为所有组别分配队员,"${emptyGroups[0].groupName ?? emptyGroups[0].name}"尚未分配`);
return; return;
@ -1848,35 +1802,35 @@ const handleStep2Next = async () => {
const groupMembers = []; const groupMembers = [];
const allTeams = []; // 用于收集所有团队数据 const allTeams = []; // 用于收集所有团队数据
const allMemberIdsSet = new Set(); const allMemberIdsSet = new Set();
for (const gId of selectedGroupIds.value) { for (const gId of selectedGroupIds.value) {
// 找到当前组别信息 // 找到当前组别信息
const group = selectedGroupItems.value.find(g => g.id === gId); const group = selectedGroupItems.value.find(g => g.id === gId);
// 检查是否为团队项目且启用了多团队模式 // 检查是否为团队项目且启用了多团队模式
const isMultiTeamMode = group && isTeamProject(group) && groupTeamsMap.value[gId] && const isMultiTeamMode = group && isTeamProject(group) && groupTeamsMap.value[gId] &&
(groupTeamsMap.value[gId].length > 1 || getGroupMaxTeams(gId) > 1); (groupTeamsMap.value[gId].length > 1 || getGroupMaxTeams(gId) > 1);
if (isMultiTeamMode) { if (isMultiTeamMode) {
// 多团队模式 // 多团队模式
const teams = groupTeamsMap.value[gId]; const teams = groupTeamsMap.value[gId];
const groupTeamsData = []; const groupTeamsData = [];
for (const team of teams) { for (const team of teams) {
const memberIds = team.members.map(m => m.userId ?? m.id); const memberIds = team.members.map(m => m.userId ?? m.id);
memberIds.forEach(id => allMemberIdsSet.add(id)); memberIds.forEach(id => allMemberIdsSet.add(id));
groupTeamsData.push({ groupTeamsData.push({
teamIndex: team.teamIndex, teamIndex: team.teamIndex,
memberIds: memberIds memberIds: memberIds
}); });
} }
groupMembers.push({ groupMembers.push({
groupId: gId, groupId: gId,
memberIds: groupTeamsData.flatMap(t => t.memberIds), // 保持向后兼容 memberIds: groupTeamsData.flatMap(t => t.memberIds), // 保持向后兼容
teams: groupTeamsData teams: groupTeamsData
}); });
allTeams.push(...groupTeamsData.map(t => ({ allTeams.push(...groupTeamsData.map(t => ({
groupId: gId, groupId: gId,
...t ...t
@ -1885,14 +1839,14 @@ const handleStep2Next = async () => {
// 单团队模式(保持向后兼容) // 单团队模式(保持向后兼容)
const memberIds = (groupMemberMap.value[gId] ?? []).map((m) => m.userId ?? m.id); const memberIds = (groupMemberMap.value[gId] ?? []).map((m) => m.userId ?? m.id);
memberIds.forEach(id => allMemberIdsSet.add(id)); memberIds.forEach(id => allMemberIdsSet.add(id));
groupMembers.push({ groupMembers.push({
groupId: gId, groupId: gId,
memberIds: memberIds memberIds: memberIds
}); });
} }
} }
const allMemberIds = [...allMemberIdsSet]; const allMemberIds = [...allMemberIdsSet];
submitDraftLoading.value = true; submitDraftLoading.value = true;
@ -1936,21 +1890,21 @@ const handleStep2Next = async () => {
const generateQRCode = async (qrcodeUrl) => { const generateQRCode = async (qrcodeUrl) => {
try { try {
await nextTick(); await nextTick();
// 清理之前的二维码 // 清理之前的二维码
if (qrcodeInstance) { if (qrcodeInstance) {
qrcodeInstance.clear(); qrcodeInstance.clear();
qrcodeInstance = null; qrcodeInstance = null;
} }
if (!qrcodeRef.value) { if (!qrcodeRef.value) {
console.error('二维码容器未找到'); console.error('二维码容器未找到');
return; return;
} }
// 清空容器 // 清空容器
qrcodeRef.value.innerHTML = ''; qrcodeRef.value.innerHTML = '';
// 创建新的二维码 // 创建新的二维码
qrcodeInstance = new QRCode(qrcodeRef.value, { qrcodeInstance = new QRCode(qrcodeRef.value, {
text: qrcodeUrl, text: qrcodeUrl,
@ -1983,7 +1937,7 @@ onUnmounted(() => {
const startPolling = (orderNo) => { const startPolling = (orderNo) => {
polling.value = true; polling.value = true;
pollingStatus.value = '等待支付...'; pollingStatus.value = '等待支付...';
pollingTimer = setInterval(async () => { pollingTimer = setInterval(async () => {
try { try {
const { succeeded, data } = await usereventregistrationOrderStatusGet(orderNo); const { succeeded, data } = await usereventregistrationOrderStatusGet(orderNo);
@ -2103,15 +2057,15 @@ const handleCreateOrderAndPay = async () => {
// 微信/支付宝支付,显示二维码 // 微信/支付宝支付,显示二维码
paymentData.value = data; paymentData.value = data;
// 检查二维码是否获取成功 // 检查二维码是否获取成功
if (!data.qrcodeUrl) { if (!data.qrcodeUrl) {
ElMessage.error('支付链接获取失败,请稍后重试'); ElMessage.error('支付链接获取失败,请稍后重试');
return; return;
} }
await generateQRCode(data.qrcodeUrl); await generateQRCode(data.qrcodeUrl);
// 开始轮询支付状态 // 开始轮询支付状态
if (data.orderNo) { if (data.orderNo) {
startPolling(data.orderNo); startPolling(data.orderNo);
@ -2228,7 +2182,8 @@ const handleCreateOrderAndPay = async () => {
font-weight: 500; font-weight: 500;
} }
&-date, &-gender { &-date,
&-gender {
color: #888; color: #888;
font-size: 12px; font-size: 12px;
} }
@ -2299,7 +2254,9 @@ const handleCreateOrderAndPay = async () => {
&-active { &-active {
border-color: #409eff; border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2); border-left: 8px solid #56b4f9;
box-shadow: 0 4px 8px rgba(64, 158, 255, 0.35);
// background: #f0f7ff;
} }
&-header { &-header {
@ -2317,6 +2274,7 @@ const handleCreateOrderAndPay = async () => {
cursor: pointer; cursor: pointer;
font-size: 16px; font-size: 16px;
opacity: 0.8; opacity: 0.8;
&:hover { &:hover {
opacity: 1; opacity: 1;
} }
@ -2369,11 +2327,11 @@ const handleCreateOrderAndPay = async () => {
cursor: pointer; cursor: pointer;
transition: all 0.2s; transition: all 0.2s;
overflow: hidden; overflow: hidden;
&:hover { &:hover {
border-color: #56b4f9; border-color: #56b4f9;
} }
&-active { &-active {
border-color: #409eff; border-color: #409eff;
box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2); box-shadow: 0 0 0 2px rgba(64, 158, 255, 0.2);