소스 검색

refactor(system): 重构分组页面逻辑

- 移除不必要的数据获取和处理逻辑
- 新增从数据库获取分组结果的功能
- 优化分组生成逻辑,支持自动生成和重新生成
- 调整页面展示,移除调试信息
- 优化代码结构,提高可读性和可维护性
zhou 13 시간 전
부모
커밋
d8179afe53
3개의 변경된 파일115개의 추가작업 그리고 229개의 파일을 삭제
  1. 22 0
      src/api/system/gameEventGroup/index.ts
  2. 2 2
      src/layout/components/Navbar.vue
  3. 91 227
      src/views/system/gameEventGroup/detail.vue

+ 22 - 0
src/api/system/gameEventGroup/index.ts

@@ -61,3 +61,25 @@ export const delGameEventGroup = (groupId: string | number | Array<string | numb
     method: 'delete'
   });
 };
+
+/**
+ * 生成分组结果
+ * @param groupId
+ */
+export const generateGroups = (groupId: string | number): AxiosPromise<any> => {
+  return request({
+    url: '/system/gameEventGroup/generateGroups/' + groupId,
+    method: 'get'
+  });
+};
+
+/**
+ * 从数据库获取分组结果
+ * @param groupId
+ */
+export const getGroupResultFromDB = (groupId: string | number): AxiosPromise<any> => {
+  return request({
+    url: '/system/gameEventGroup/getGroupResultFromDB/' + groupId,
+    method: 'get'
+  });
+};

+ 2 - 2
src/layout/components/Navbar.vue

@@ -274,9 +274,9 @@ watch(
     gap: 8px;
     padding: 0 16px;
     height: 100%;
-    background: rgba(64, 158, 255, 0.1);
+    background: rgba(246, 246, 247, 0.1);
     border-radius: 4px;
-    border: 1px solid rgba(64, 158, 255, 0.2);
+    border: 1px solid rgba(249, 251, 252, 0.2);
     
     .event-icon {
       font-size: 16px;

+ 91 - 227
src/views/system/gameEventGroup/detail.vue

@@ -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);