赛事记录-更换队员筛选
This commit is contained in:
parent
bca23b5d65
commit
26b98ef2a4
@ -272,4 +272,43 @@ export const usereventrecordDetailWithItemsGet = (registrationId) => {
|
||||
*/
|
||||
export const usereventrecordUpdateMembersPost = (data) => {
|
||||
return http.post('/usereventrecord/update-members', data);
|
||||
};
|
||||
|
||||
/**
|
||||
* 11. 验证队员是否符合报名条件
|
||||
* @param {Object} data - 验证信息
|
||||
* @param {number} data.eventId - 赛事ID
|
||||
* @param {number} data.memberId - 队员ID
|
||||
* @param {number} data.groupId - 组别ID
|
||||
* @returns {Promise<{
|
||||
* isValid: boolean,
|
||||
* ageValid: boolean,
|
||||
* genderValid: boolean,
|
||||
* registrationLimitValid: boolean,
|
||||
* message: string
|
||||
* }>}
|
||||
*/
|
||||
export const usereventrecordMemberValidatePost = (data) => {
|
||||
return http.post('/usereventrecord/member/validate', data);
|
||||
};
|
||||
|
||||
/**
|
||||
* 12. 检查报名限制
|
||||
* @param {Object} data - 检查信息
|
||||
* @param {number} data.eventId - 赛事ID
|
||||
* @param {Array<number>} data.memberIds - 队员ID列表
|
||||
* @param {Array<number>} data.groupIds - 组别ID列表
|
||||
* @param {Array<{groupId: number, memberIds: Array<number>}>} data.groupMembers - 组别队员分配
|
||||
* @returns {Promise<{
|
||||
* hasLimit: boolean,
|
||||
* limitDetails: Array<{
|
||||
* memberId: number,
|
||||
* memberName: string,
|
||||
* limitType: string,
|
||||
* limitMessage: string
|
||||
* }>
|
||||
* }>}
|
||||
*/
|
||||
export const usereventrecordRegistrationLimitCheckPost = (data) => {
|
||||
return http.post('/usereventrecord/registration-limit/check', data);
|
||||
};
|
||||
@ -274,13 +274,14 @@
|
||||
@click="activeChangeItemGroupId = item.registrationItemId"
|
||||
>
|
||||
<div class="assign-card-header">
|
||||
<span>{{ formatItemTitle(item) }}</span>
|
||||
</div>
|
||||
<span>{{ formatItemTitle(item) }}</span>
|
||||
</div>
|
||||
<div class="assign-card-members">
|
||||
<el-tag
|
||||
v-for="m in (changeMembersMap[item.registrationItemId] ?? [])"
|
||||
:key="m.userId ?? m.id"
|
||||
closable
|
||||
:type="getMemberValidationResult(m, item).isValid ? '' : 'danger'"
|
||||
@close="removeMemberFromChangeGroup(item.registrationItemId, m.userId ?? m.id)"
|
||||
style="margin: 3px;"
|
||||
>
|
||||
@ -288,6 +289,18 @@
|
||||
</el-tag>
|
||||
<span v-if="!(changeMembersMap[item.registrationItemId]?.length)" class="assign-card-placeholder">点击此卡片后,从右侧选择队员</span>
|
||||
</div>
|
||||
|
||||
<!-- 队员验证错误提示 -->
|
||||
<div v-if="hasValidationErrorsForItem(item)" class="validation-error-section">
|
||||
<div class="validation-error-item"
|
||||
v-for="m in (changeMembersMap[item.registrationItemId] ?? [])"
|
||||
:key="m.userId ?? m.id">
|
||||
<el-alert v-if="!getMemberValidationResult(m, item).isValid"
|
||||
:title="getMemberValidationResult(m, item).message"
|
||||
type="error" :closable="false"
|
||||
size="small" style="margin-top: 4px;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-if="!changeMembersItems.length" description="暂无项目" />
|
||||
</div>
|
||||
@ -328,6 +341,19 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 验证提示区域 -->
|
||||
<div class="validation-notes-section" style="margin-top: 16px;">
|
||||
<!-- 年龄性别不符合要求提示 -->
|
||||
<el-alert v-if="hasAnyValidationErrors()" title="队员信息不符合组别要求" type="error" :closable="false" style="margin-bottom: 12px;" />
|
||||
|
||||
<!-- 限报提示 -->
|
||||
<template v-if="hasAnyRegistrationLimit()">
|
||||
<el-alert v-for="(detail, index) in (registrationLimitCheckResult?.limitDetails ?? [])"
|
||||
:key="index" :title="detail?.limitMessage ?? '报名限制'"
|
||||
type="warning" :closable="false" style="margin-bottom: 12px;" />
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<el-empty v-else description="暂无数据" />
|
||||
</template>
|
||||
@ -335,7 +361,7 @@
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="isShowChangeMembersDialog = false">取消</el-button>
|
||||
<el-button type="primary" @click="previewChangeMembers">预览</el-button>
|
||||
<el-button type="primary" @click="previewChangeMembers" :disabled="hasAnyValidationErrors() || hasAnyRegistrationLimit()">预览</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
@ -516,7 +542,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, reactive, ref, watch } from 'vue';
|
||||
import { computed, reactive, ref, watch, nextTick } from 'vue';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { UploadFilled, ArrowRight, Close, CircleCheck } from '@element-plus/icons-vue';
|
||||
import ProTable from '/@/components/ProTable/index.vue';
|
||||
@ -532,6 +558,8 @@ import {
|
||||
usereventrecordCancelExecutePost,
|
||||
usereventrecordDetailWithItemsGet,
|
||||
usereventrecordUpdateMembersPost,
|
||||
usereventrecordMemberValidatePost,
|
||||
usereventrecordRegistrationLimitCheckPost,
|
||||
} from '/@/api/match/usereventrecord';
|
||||
import { teamPageGet, teamDetailGet } from '/@/api/match/unitUser';
|
||||
|
||||
@ -1207,6 +1235,37 @@ const selectedChangeTeamId = ref(null);
|
||||
const changeTeamMembers = ref([]);
|
||||
const changeTeamMemberLoading = ref(false);
|
||||
|
||||
// 队员验证相关
|
||||
const memberValidationMap = ref({}); // { registrationItemId_memberId: validationResult }
|
||||
const registrationLimitCheckResult = ref(null); // 报名限制检查结果
|
||||
const validationLoading = ref(false); // 验证加载状态
|
||||
let validationDebounceTimer = null; // 防抖定时器
|
||||
|
||||
// 获取队员验证结果
|
||||
const getMemberValidationResult = (member, item) => {
|
||||
const key = `${item.registrationItemId}_${member.userId ?? member.id}`;
|
||||
return memberValidationMap.value[key] || { isValid: true, ageValid: true, genderValid: true, registrationLimitValid: true, message: '' };
|
||||
};
|
||||
|
||||
// 检查某个项目是否有验证错误
|
||||
const hasValidationErrorsForItem = (item) => {
|
||||
const members = changeMembersMap.value[item.registrationItemId] || [];
|
||||
return members.some(member => {
|
||||
const result = getMemberValidationResult(member, item);
|
||||
return !result.isValid;
|
||||
});
|
||||
};
|
||||
|
||||
// 检查是否有任何验证错误
|
||||
const hasAnyValidationErrors = () => {
|
||||
return changeMembersItems.value.some(item => hasValidationErrorsForItem(item));
|
||||
};
|
||||
|
||||
// 检查是否有任何报名限制
|
||||
const hasAnyRegistrationLimit = () => {
|
||||
return registrationLimitCheckResult.value?.hasLimit ?? false;
|
||||
};
|
||||
|
||||
const openViewChangeMembersDialog = async (row) => {
|
||||
if (!row?.registrationId) return;
|
||||
isShowViewChangeMembersDialog.value = true;
|
||||
@ -1248,7 +1307,7 @@ const openChangeMembersDialog = async () => {
|
||||
// 初始化 changeMembersMap
|
||||
changeMembersItems.value.forEach(item => {
|
||||
changeMembersMap.value[item.registrationItemId] = (item.members || []).map(m => ({
|
||||
userId: m.id,
|
||||
userId: m.userId, // 使用正确的userId
|
||||
id: m.id,
|
||||
name: m.name,
|
||||
gender: m.gender,
|
||||
@ -1281,6 +1340,15 @@ const onChangeMembersDialogClosed = () => {
|
||||
changeTeamList.value = [];
|
||||
selectedChangeTeamId.value = null;
|
||||
changeTeamMembers.value = [];
|
||||
|
||||
// 重置验证相关状态
|
||||
memberValidationMap.value = {};
|
||||
registrationLimitCheckResult.value = null;
|
||||
validationLoading.value = false;
|
||||
if (validationDebounceTimer) {
|
||||
clearTimeout(validationDebounceTimer);
|
||||
validationDebounceTimer = null;
|
||||
}
|
||||
};
|
||||
|
||||
const fetchChangeTeamList = async () => {
|
||||
@ -1330,6 +1398,106 @@ const isChangeMemberAssignedToActive = (memberId) => {
|
||||
return list.some((m) => (m.userId ?? m.id) === memberId);
|
||||
};
|
||||
|
||||
// ==================== 队员验证相关函数 ====================
|
||||
|
||||
// 调用后端API验证队员
|
||||
const validateMemberForItem = async (member, item) => {
|
||||
try {
|
||||
// 添加调试信息
|
||||
console.log('验证队员 - member:', member);
|
||||
console.log('验证队员 - member.userId:', member.userId);
|
||||
console.log('验证队员 - member.id:', member.id);
|
||||
console.log('验证队员 - item.eventProjectGroupId:', item.eventProjectGroupId);
|
||||
|
||||
const payload = {
|
||||
eventId: changeMembersData.value.eventId,
|
||||
memberId: member.userId ?? member.id,
|
||||
groupId: item.eventProjectGroupId
|
||||
};
|
||||
console.log('验证队员 - payload:', payload);
|
||||
|
||||
const { succeeded, data } = await usereventrecordMemberValidatePost(payload);
|
||||
console.log('验证队员 - response:', { succeeded, data });
|
||||
|
||||
if (succeeded && data) {
|
||||
const key = `${item.registrationItemId}_${member.userId ?? member.id}`;
|
||||
memberValidationMap.value[key] = data;
|
||||
return data;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error('验证队员失败:', e);
|
||||
}
|
||||
|
||||
return { isValid: true, ageValid: true, genderValid: true, registrationLimitValid: true, message: '' };
|
||||
};
|
||||
|
||||
// 实时验证所有已选择的队员
|
||||
const validateAllMembers = async () => {
|
||||
if (!changeMembersData.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
validationLoading.value = true;
|
||||
|
||||
try {
|
||||
// 收集所有需要验证的队员和项目组合
|
||||
const validationTasks = [];
|
||||
let hasAnyMembers = false;
|
||||
|
||||
for (const item of changeMembersItems.value) {
|
||||
const members = changeMembersMap.value[item.registrationItemId] || [];
|
||||
|
||||
if (members.length > 0) {
|
||||
hasAnyMembers = true;
|
||||
}
|
||||
|
||||
// 为每个队员创建验证任务
|
||||
for (const member of members) {
|
||||
validationTasks.push(validateMemberForItem(member, item));
|
||||
}
|
||||
}
|
||||
|
||||
// 并行执行所有验证任务
|
||||
await Promise.all(validationTasks);
|
||||
|
||||
// 只有在有队员的情况下才检查报名限制
|
||||
if (hasAnyMembers) {
|
||||
// 构建报名限制检查的参数
|
||||
const groupMembers = changeMembersItems.value.map(item => ({
|
||||
groupId: item.eventProjectGroupId,
|
||||
memberIds: (changeMembersMap.value[item.registrationItemId] || []).map(m => m.userId ?? m.id)
|
||||
}));
|
||||
|
||||
// 检查报名限制
|
||||
const { succeeded, data } = await usereventrecordRegistrationLimitCheckPost({
|
||||
eventId: changeMembersData.value.eventId,
|
||||
groupMembers: groupMembers
|
||||
});
|
||||
|
||||
if (succeeded && data) {
|
||||
registrationLimitCheckResult.value = data;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('批量验证队员失败:', error);
|
||||
} finally {
|
||||
validationLoading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 带防抖的实时验证
|
||||
const debounceValidateAllMembers = () => {
|
||||
if (validationDebounceTimer) {
|
||||
clearTimeout(validationDebounceTimer);
|
||||
}
|
||||
|
||||
validationDebounceTimer = setTimeout(() => {
|
||||
validateAllMembers();
|
||||
}, 400); // 400毫秒防抖
|
||||
};
|
||||
|
||||
// ==================== 队员分配函数 ====================
|
||||
|
||||
const assignMemberToChangeActiveTeam = (member) => {
|
||||
const gId = activeChangeItemGroupId.value;
|
||||
if (!gId) {
|
||||
@ -1344,11 +1512,17 @@ const assignMemberToChangeActiveTeam = (member) => {
|
||||
return;
|
||||
}
|
||||
changeMembersMap.value[gId].push({ ...member });
|
||||
|
||||
// 触发实时验证
|
||||
debounceValidateAllMembers();
|
||||
};
|
||||
|
||||
const removeMemberFromChangeGroup = (groupId, memberId) => {
|
||||
if (!changeMembersMap.value[groupId]) return;
|
||||
changeMembersMap.value[groupId] = changeMembersMap.value[groupId].filter((m) => (m.userId ?? m.id) !== memberId);
|
||||
|
||||
// 触发实时验证
|
||||
debounceValidateAllMembers();
|
||||
};
|
||||
|
||||
const previewChangeMembers = () => {
|
||||
@ -1412,6 +1586,18 @@ const submitChangeMembers = async () => {
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.validation-notes-section {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.validation-error-section {
|
||||
padding: 0 14px 14px;
|
||||
}
|
||||
|
||||
.validation-error-item {
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.step2-left {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user