|
@@ -15,7 +15,7 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="text-right">
|
|
|
- <el-button type="primary" @click="generateGroups" :loading="generating">重新生成分组</el-button>
|
|
|
+ <el-button type="primary" @click="regenerateGroups" :loading="generating">重新生成分组</el-button>
|
|
|
<el-button @click="goBack">返回</el-button>
|
|
|
</div>
|
|
|
</div>
|
|
@@ -106,36 +106,15 @@
|
|
|
</div>
|
|
|
</el-card>
|
|
|
|
|
|
- <!-- 调试信息 -->
|
|
|
- <!-- <el-card shadow="hover" class="mt-4">
|
|
|
- <template #header>
|
|
|
- <span class="font-medium">调试信息</span>
|
|
|
- </template>
|
|
|
-
|
|
|
- <div class="space-y-2 text-sm">
|
|
|
- <div><strong>项目ID:</strong> {{ groupInfo.projectId }}</div>
|
|
|
- <div><strong>性别要求:</strong> {{ groupInfo.memberGender === '0' ? '不分男女' : groupInfo.memberGender === '1' ? '男' : '女' }}</div>
|
|
|
- <div><strong>运动员总数:</strong> {{ athletes.length }}</div>
|
|
|
- <div><strong>符合条件的运动员数:</strong> {{ totalAthletes }}</div>
|
|
|
- <div><strong>分组结果大小:</strong> {{ groupResult.size }}</div>
|
|
|
- <div><strong>分组结果:</strong></div>
|
|
|
- <pre class="bg-gray-100 p-2 rounded text-xs overflow-auto max-h-40">{{ JSON.stringify(Array.from(groupResult.entries()), null, 2) }}</pre>
|
|
|
- </div>
|
|
|
- </el-card> -->
|
|
|
+
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
|
<script setup name="GameEventGroupDetail" lang="ts">
|
|
|
-import { ref, onMounted, computed, getCurrentInstance } from 'vue';
|
|
|
+import { ref, onMounted, getCurrentInstance } from 'vue';
|
|
|
import { useRoute, useRouter } from 'vue-router';
|
|
|
-import { getGameEventGroup } from '@/api/system/gameEventGroup';
|
|
|
-import { listGameAthlete } from '@/api/system/gameAthlete';
|
|
|
-import { listGameTeam } from '@/api/system/gameTeam';
|
|
|
-import { listGameEventProject } from '@/api/system/gameEventProject';
|
|
|
+import { getGameEventGroup, generateGroups, getGroupResultFromDB } from '@/api/system/gameEventGroup';
|
|
|
import { GameEventGroupVO } from '@/api/system/gameEventGroup/types';
|
|
|
-import { GameAthleteVO } from '@/api/system/gameAthlete/types';
|
|
|
-import { GameTeamVO } from '@/api/system/gameTeam/types';
|
|
|
-import { GameEventProjectVO } from '@/api/system/gameEventProject/types';
|
|
|
import type { ComponentInternalInstance } from 'vue';
|
|
|
|
|
|
const route = useRoute();
|
|
@@ -144,76 +123,18 @@ const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
|
|
|
// 分组信息
|
|
|
const groupInfo = ref<GameEventGroupVO>({} as GameEventGroupVO);
|
|
|
-// 运动员列表
|
|
|
-const athletes = ref<GameAthleteVO[]>([]);
|
|
|
-// 队伍列表
|
|
|
-const teams = ref<GameTeamVO[]>([]);
|
|
|
-// 项目列表
|
|
|
-const projects = ref<GameEventProjectVO[]>([]);
|
|
|
// 分组结果
|
|
|
-const groupResult = ref<Map<string, GameAthleteVO>>(new Map());
|
|
|
+const groupResult = ref<Map<string, any>>(new Map());
|
|
|
// 加载状态
|
|
|
const loading = ref(false);
|
|
|
// 生成分组状态
|
|
|
const generating = ref(false);
|
|
|
|
|
|
-const roundType = ref();
|
|
|
-// 项目名称(需要从项目信息中获取)
|
|
|
-const projectName = computed(() => {
|
|
|
- if (!groupInfo.value.projectId) return '';
|
|
|
- const project = projects.value.find(p => p.projectId === groupInfo.value.projectId);
|
|
|
- roundType.value = project?.roundType || 0;
|
|
|
- return project?.projectName || '';
|
|
|
-});
|
|
|
-
|
|
|
-// 计算总运动员数
|
|
|
-const totalAthletes = computed(() => {
|
|
|
- return athletes.value.filter(athlete => {
|
|
|
- // 检查运动员是否参与该项目
|
|
|
- if (!athlete.projectList) return false;
|
|
|
-
|
|
|
- // 处理项目列表
|
|
|
- let projectIds: string[] = [];
|
|
|
- if (Array.isArray(athlete.projectList)) {
|
|
|
- projectIds = athlete.projectList.map(p => p.toString());
|
|
|
- } else if (typeof athlete.projectList === 'string') {
|
|
|
- try {
|
|
|
- projectIds = JSON.parse(athlete.projectList);
|
|
|
- } catch (e) {
|
|
|
- // 如果不是JSON格式,可能是逗号分隔的字符串
|
|
|
- projectIds = (athlete.projectList as string).split(',').map(p => p.trim());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- const targetProjectId = groupInfo.value.projectId?.toString();
|
|
|
- const hasProject = projectIds.includes(targetProjectId);
|
|
|
-
|
|
|
- if (!hasProject) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查性别是否匹配
|
|
|
- if (groupInfo.value.memberGender && groupInfo.value.memberGender !== '0') {
|
|
|
- // 使用字典来匹配性别,而不是硬编码的字符串
|
|
|
- if (athlete.gender?.toString() !== groupInfo.value.memberGender?.toString()) {
|
|
|
- return false;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- return true;
|
|
|
- }).length;
|
|
|
-});
|
|
|
-
|
|
|
-// 调试:打印运动员数据
|
|
|
-const debugAthletes = computed(() => {
|
|
|
- return athletes.value.map(athlete => ({
|
|
|
- id: athlete.athleteId,
|
|
|
- name: athlete.name,
|
|
|
- teamId: athlete.teamId,
|
|
|
- projectList: athlete.projectList,
|
|
|
- gender: athlete.gender
|
|
|
- }));
|
|
|
-});
|
|
|
+// 项目名称和录取人数
|
|
|
+const projectName = ref('');
|
|
|
+const roundType = ref(0);
|
|
|
+// 总运动员数
|
|
|
+const totalAthletes = ref(0);
|
|
|
|
|
|
// 获取道次名称
|
|
|
const getTrackName = (track: number) => {
|
|
@@ -229,8 +150,9 @@ const getAthleteByGroupAndTrack = (groupIndex: number, track: number) => {
|
|
|
|
|
|
// 根据队伍ID获取队伍名称
|
|
|
const getTeamName = (teamId: string | number | undefined) => {
|
|
|
- if (!teamId) return '';
|
|
|
- const team = teams.value.find(t => t.teamId === teamId);
|
|
|
+ if (!groupResult.value.has('teams')) return '';
|
|
|
+ const teams = groupResult.value.get('teams') || [];
|
|
|
+ const team = teams.find((t: any) => t.teamId === teamId);
|
|
|
return team?.teamName || '';
|
|
|
};
|
|
|
|
|
@@ -247,15 +169,8 @@ const getGroupInfo = async () => {
|
|
|
const res = await getGameEventGroup(groupId);
|
|
|
groupInfo.value = res.data;
|
|
|
|
|
|
- // 获取运动员、队伍和项目信息
|
|
|
- await Promise.all([
|
|
|
- getAthletes(),
|
|
|
- getTeams(),
|
|
|
- getProjects()
|
|
|
- ]);
|
|
|
-
|
|
|
- // 生成分组
|
|
|
- generateGroups();
|
|
|
+ // 优先从数据库读取分组数据
|
|
|
+ await loadGroupResultFromDB();
|
|
|
} catch (error) {
|
|
|
console.error('获取分组信息失败:', error);
|
|
|
proxy?.$modal.msgError('获取分组信息失败');
|
|
@@ -264,153 +179,97 @@ const getGroupInfo = async () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
-// 获取运动员列表
|
|
|
-const getAthletes = async () => {
|
|
|
- try {
|
|
|
- const res = await listGameAthlete({
|
|
|
- pageNum: 1,
|
|
|
- pageSize: 1000,
|
|
|
- eventId: groupInfo.value.eventId,
|
|
|
- orderByColumn: '',
|
|
|
- isAsc: ''
|
|
|
- });
|
|
|
- athletes.value = res.rows;
|
|
|
- } catch (error) {
|
|
|
- console.error('获取运动员列表失败:', error);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 获取队伍列表
|
|
|
-const getTeams = async () => {
|
|
|
+// 从数据库加载分组结果
|
|
|
+const loadGroupResultFromDB = async () => {
|
|
|
try {
|
|
|
- const res = await listGameTeam({
|
|
|
- pageNum: 1,
|
|
|
- pageSize: 1000,
|
|
|
- eventId: groupInfo.value.eventId,
|
|
|
- orderByColumn: '',
|
|
|
- isAsc: ''
|
|
|
- });
|
|
|
- teams.value = res.rows;
|
|
|
- } catch (error) {
|
|
|
- console.error('获取队伍列表失败:', error);
|
|
|
- }
|
|
|
-};
|
|
|
-
|
|
|
-// 获取项目列表
|
|
|
-const getProjects = async () => {
|
|
|
- try {
|
|
|
- const res = await listGameEventProject({
|
|
|
- pageNum: 1,
|
|
|
- pageSize: 1000,
|
|
|
- orderByColumn: '',
|
|
|
- isAsc: ''
|
|
|
- });
|
|
|
- projects.value = res.rows;
|
|
|
+ const groupId = route.query.id;
|
|
|
+ if (!groupId || Array.isArray(groupId)) {
|
|
|
+ proxy?.$modal.msgError('分组ID不能为空');
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const res = await getGroupResultFromDB(groupId);
|
|
|
+ const data = res.data;
|
|
|
+
|
|
|
+ if (data.success) {
|
|
|
+ // 更新分组结果
|
|
|
+ groupResult.value.clear();
|
|
|
+
|
|
|
+ // 设置分组结果
|
|
|
+ if (data.groupResult) {
|
|
|
+ Object.entries(data.groupResult).forEach(([key, athlete]) => {
|
|
|
+ groupResult.value.set(key, athlete);
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ if (data.totalAthletes !== undefined) {
|
|
|
+ totalAthletes.value = data.totalAthletes;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 设置项目信息(从分组信息中获取)
|
|
|
+ if (groupInfo.value.projectId) {
|
|
|
+ // 这里可以根据需要设置项目名称和录取人数
|
|
|
+ projectName.value = '项目名称'; // 需要根据实际情况获取
|
|
|
+ roundType.value = 0; // 需要根据实际情况获取
|
|
|
+ }
|
|
|
+
|
|
|
+ console.log('从数据库加载分组结果成功');
|
|
|
+ } else {
|
|
|
+ // 数据库中没有数据,自动生成分组
|
|
|
+ console.log('数据库中没有分组数据,自动生成分组');
|
|
|
+ await generateGroupsData();
|
|
|
+ }
|
|
|
} catch (error) {
|
|
|
- console.error('获取项目列表失败:', error);
|
|
|
+ console.error('从数据库加载分组结果失败:', error);
|
|
|
+ // 加载失败时,自动生成分组
|
|
|
+ await generateGroupsData();
|
|
|
}
|
|
|
};
|
|
|
|
|
|
// 生成分组
|
|
|
-const generateGroups = async () => {
|
|
|
+const generateGroupsData = async () => {
|
|
|
try {
|
|
|
generating.value = true;
|
|
|
|
|
|
- // 清空之前的分组结果
|
|
|
- groupResult.value.clear();
|
|
|
+ const groupId = route.query.id;
|
|
|
+ if (!groupId || Array.isArray(groupId)) {
|
|
|
+ proxy?.$modal.msgError('分组ID不能为空');
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- // 筛选符合条件的运动员
|
|
|
- const eligibleAthletes = athletes.value.filter(athlete => {
|
|
|
+ const res = await generateGroups(groupId);
|
|
|
+ const data = res.data;
|
|
|
+
|
|
|
+ if (data.success) {
|
|
|
+ // 更新分组结果
|
|
|
+ groupResult.value.clear();
|
|
|
|
|
|
- // 检查是否参与该项目
|
|
|
- if (!athlete.projectList) {
|
|
|
- return false;
|
|
|
+ // 设置分组结果
|
|
|
+ if (data.groupResult) {
|
|
|
+ Object.entries(data.groupResult).forEach(([key, athlete]) => {
|
|
|
+ groupResult.value.set(key, athlete);
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
- // 处理项目列表
|
|
|
- let projectIds: string[] = [];
|
|
|
- if (Array.isArray(athlete.projectList)) {
|
|
|
- projectIds = athlete.projectList.map(p => p.toString());
|
|
|
- } else if (typeof athlete.projectList === 'string') {
|
|
|
- try {
|
|
|
- projectIds = JSON.parse(athlete.projectList);
|
|
|
- } catch (e) {
|
|
|
- // 如果不是JSON格式,可能是逗号分隔的字符串
|
|
|
- projectIds = (athlete.projectList as string).split(',').map(p => p.trim());
|
|
|
- }
|
|
|
+ // 设置其他数据
|
|
|
+ if (data.project) {
|
|
|
+ projectName.value = data.project.projectName || '';
|
|
|
+ roundType.value = data.project.roundType || 0;
|
|
|
}
|
|
|
|
|
|
- const targetProjectId = groupInfo.value.projectId?.toString();
|
|
|
- const hasProject = projectIds.includes(targetProjectId);
|
|
|
-
|
|
|
- if (!hasProject) {
|
|
|
- return false;
|
|
|
+ if (data.totalAthletes !== undefined) {
|
|
|
+ totalAthletes.value = data.totalAthletes;
|
|
|
}
|
|
|
|
|
|
- // 检查性别是否匹配
|
|
|
- if (groupInfo.value.memberGender && groupInfo.value.memberGender !== '0') {
|
|
|
- // 使用字典来匹配性别,而不是硬编码的字符串
|
|
|
- if (athlete.gender?.toString() !== groupInfo.value.memberGender?.toString()) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+ // 设置队伍信息
|
|
|
+ if (data.teams) {
|
|
|
+ groupResult.value.set('teams', data.teams);
|
|
|
}
|
|
|
|
|
|
- return true;
|
|
|
- });
|
|
|
-
|
|
|
- if (eligibleAthletes.length === 0) {
|
|
|
- proxy?.$modal.msgWarning('没有找到符合条件的运动员');
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // 随机打乱运动员顺序
|
|
|
- const shuffledAthletes = [...eligibleAthletes].sort(() => Math.random() - 0.5);
|
|
|
-
|
|
|
- // 记录已分配的运动员ID,避免重复分配
|
|
|
- const assignedAthleteIds = new Set();
|
|
|
-
|
|
|
- // 按组别和道次分配运动员
|
|
|
- for (let groupIndex = 1; groupIndex <= groupInfo.value.includeGroupNum; groupIndex++) {
|
|
|
- for (let track = 1; track <= groupInfo.value.trackNum; track++) {
|
|
|
- // 寻找可用的运动员
|
|
|
- let selectedAthlete = null;
|
|
|
- let athleteIndex = 0;
|
|
|
-
|
|
|
- while (athleteIndex < shuffledAthletes.length && !selectedAthlete) {
|
|
|
- const candidateAthlete = shuffledAthletes[athleteIndex];
|
|
|
-
|
|
|
- // 检查运动员是否已经被分配
|
|
|
- if (assignedAthleteIds.has(candidateAthlete.athleteId)) {
|
|
|
- athleteIndex++;
|
|
|
- continue;
|
|
|
- }
|
|
|
-
|
|
|
- // 检查同一组中是否已有同一队伍的运动员
|
|
|
- const hasSameTeamInGroup = Array.from(groupResult.value.entries())
|
|
|
- .some(([key, existingAthlete]) => {
|
|
|
- const [existingGroup] = key.split('-');
|
|
|
- return existingGroup === groupIndex.toString() &&
|
|
|
- existingAthlete.teamId === candidateAthlete.teamId;
|
|
|
- });
|
|
|
-
|
|
|
- if (!hasSameTeamInGroup) {
|
|
|
- selectedAthlete = candidateAthlete;
|
|
|
- // 标记运动员为已分配
|
|
|
- assignedAthleteIds.add(candidateAthlete.athleteId);
|
|
|
- }
|
|
|
-
|
|
|
- athleteIndex++;
|
|
|
- }
|
|
|
-
|
|
|
- // 如果找到了合适的运动员,分配到当前组和道次
|
|
|
- if (selectedAthlete) {
|
|
|
- const key = `${groupIndex}-${track}`;
|
|
|
- groupResult.value.set(key, selectedAthlete);
|
|
|
- }
|
|
|
- }
|
|
|
+ proxy?.$modal.msgSuccess('分组生成成功');
|
|
|
+ } else {
|
|
|
+ proxy?.$modal.msgWarning(data.message || '生成分组失败');
|
|
|
}
|
|
|
-
|
|
|
- proxy?.$modal.msgSuccess('分组生成成功');
|
|
|
} catch (error) {
|
|
|
console.error('生成分组失败:', error);
|
|
|
proxy?.$modal.msgError('生成分组失败');
|
|
@@ -419,6 +278,11 @@ const generateGroups = async () => {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+// 重新生成分组
|
|
|
+const regenerateGroups = async () => {
|
|
|
+ await generateGroupsData();
|
|
|
+};
|
|
|
+
|
|
|
// 返回上一页
|
|
|
const goBack = () => {
|
|
|
router.go(-1);
|