Browse Source

Merge branch 'dev' into wk-dev

wenkai 1 week ago
parent
commit
934c7de4a3

+ 119 - 0
src/api/system/gameEventGroup/types.ts

@@ -45,6 +45,46 @@ export interface GameEventGroupVO {
    */
   remark: string;
 
+  /**
+   * 包含组数
+   */
+  includeGroupNum: number;
+
+  /**
+   * 项目id
+   */
+  projectId: string | number;
+
+  /**
+   * 人数/组别
+   */
+  personNum: number;
+
+  /**
+   * 组别比赛开始时间
+   */
+  beginTime: string;
+
+  /**
+   * 组别比赛结束时间
+   */
+  endTime: string;
+
+  /**
+   * 道数
+   */
+  trackNum: number;
+
+  /**
+   * 场地数量
+   */
+  fieldNum: number;
+
+  /**
+   * 每组用时
+   */
+  duration: number;
+
 }
 
 export interface GameEventGroupForm extends BaseEntity {
@@ -98,6 +138,45 @@ export interface GameEventGroupForm extends BaseEntity {
    */
   remark?: string;
 
+  /**
+   * 包含组数
+   */
+  includeGroupNum?: number;
+
+  /**
+   * 项目id
+   */
+  projectId?: string | number;
+
+  /**
+   * 人数/组别
+   */
+  personNum?: number;
+
+  /**
+   * 组别比赛开始时间
+   */
+  beginTime?: string;
+
+  /**
+   * 组别比赛结束时间
+   */
+  endTime?: string;
+
+  /**
+   * 道数
+   */
+  trackNum?: number;
+
+  /**
+   * 场地数量
+   */
+  fieldNum?: number;
+
+  /**
+   * 每组用时
+   */
+  duration?: number;
 }
 
 export interface GameEventGroupQuery extends PageQuery {
@@ -137,6 +216,46 @@ export interface GameEventGroupQuery extends PageQuery {
    */
   status?: string;
 
+  /**
+   * 包含组数
+   */
+  includeGroupNum?: number;
+
+  /**
+   * 项目id
+   */
+  projectId?: string | number;
+
+  /**
+   * 人数/组别
+   */
+  personNum?: number;
+
+  /**
+   * 组别比赛开始时间
+   */
+  beginTime?: string;
+
+  /**
+   * 组别比赛结束时间
+   */
+  endTime?: string;
+
+  /**
+   * 道数
+   */
+  trackNum?: number;
+
+  /**
+   * 场地数量
+   */
+  fieldNum?: number;
+
+  /**
+   * 每组用时
+   */
+  duration?: number;
+
   /**
    * 日期范围参数
    */

+ 13 - 0
src/router/index.ts

@@ -157,6 +157,19 @@ export const constantRoutes: RouteRecordRaw[] = [
         meta: { title: '日程管理', icon: 'form' }
       },
     ]
+  },
+  {
+    path: '/system/gameEventGroup',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'detail',
+        component: () => import('@/views/system/gameEventGroup/detail.vue'),
+        name: 'GameEventGroupDetail',
+        meta: { title: '分组详情', icon: 'view' }
+      }
+    ]
   }
 ];
 

+ 104 - 87
src/views/system/gameEvent/index.vue

@@ -56,101 +56,47 @@
           <el-col :span="1.5">
             <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['system:gameEvent:export']">导出 </el-button>
           </el-col>
+          <!-- 新增的操作按钮,基于默认赛事 -->
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="Download" @click="handleDownloadTemplateDefault" v-hasPermi="['system:gameEvent:download']">下载模板</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="info" plain icon="FolderOpened" @click="handleImportRegistrationDefault" v-hasPermi="['system:gameEvent:import']">导入报名</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="success" plain icon="User" @click="handleAddParticipantDefault" v-hasPermi="['system:gameEvent:addParticipant']">参赛者</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="Avatar" @click="handleAddRefereeDefault" v-hasPermi="['system:gameEvent:addReferee']">裁判</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="info" plain icon="View" @click="handlePreviewDefault" v-hasPermi="['system:gameEvent:view']">预览</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="warning" plain icon="DataAnalysis" @click="handleGameDataDefault" v-hasPermi="['system:gameEvent:gameData']">排行榜</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="primary" plain icon="EditPen" @click="handleWriteArticleDefault" v-hasPermi="['system:gameEvent:writeArticle']">编写文章</el-button>
+          </el-col>
           <right-toolbar v-model:showSearch="showSearch" :columns="columns" @queryTable="getList"></right-toolbar>
         </el-row>
       </template>
 
       <el-table v-loading="loading" border :data="gameEventList" @selection-change="handleSelectionChange">
+        <!-- 第一列:多选列 -->
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" fixed="left" width="220">
+        
+        <!-- 第二列:操作列 -->
+        <el-table-column label="操作" align="center" class-name="small-padding fixed-width" width="120">
           <template #default="scope">
-            <div class="operation-buttons">
-              <!-- 第一行:基本操作 -->
-              <div class="button-row">
-                <el-tooltip content="修改" placement="top">
-                  <el-button link type="primary" icon="Edit" size="small" @click="handleUpdate(scope.row)" v-hasPermi="['system:gameEvent:edit']"></el-button>
-                </el-tooltip>
-                <el-tooltip :content="getDeleteTooltip(scope.row)" placement="top">
-                  <el-button
-                    link
-                    type="danger"
-                    icon="Delete"
-                    size="small"
-                    :disabled="!canDelete(scope.row)"
-                    @click="handleDelete(scope.row)"
-                    v-hasPermi="['system:event:remove']"
-                  ></el-button>
-                </el-tooltip>
-                <el-tooltip content="预览" placement="top">
-                  <el-button link type="primary" icon="View" size="small" @click="handlePreview(scope.row)" v-hasPermi="['system:gameEvent:view']"></el-button>
-                </el-tooltip>
-                <el-tooltip content="比赛数据" placement="top">
-                  <el-button
-                    link
-                    type="success"
-                    icon="DataAnalysis"
-                    size="small"
-                    @click="handleGameData(scope.row)"
-                    v-hasPermi="['system:gameEvent:gameData']"
-                  ></el-button>
-                </el-tooltip>
-              </div>
-
-              <!-- 第二行:管理操作 -->
-              <div class="button-row">
-                <el-tooltip content="下载模板" placement="top">
-                  <el-button link type="info" icon="Download" size="small" @click="handleDownloadTemplate(scope.row)"></el-button>
-                </el-tooltip>
-                <el-tooltip content="导入报名" placement="top">
-                  <el-button
-                    link
-                    type="warning"
-                    icon="FolderOpened"
-                    size="small"
-                    @click="handleImportRegistration(scope.row)"
-                    v-hasPermi="['system:gameEvent:import']"
-                  ></el-button>
-                </el-tooltip>
-                <el-tooltip content="添加参赛者" placement="top">
-                  <el-button
-                    link
-                    type="primary"
-                    icon="User"
-                    size="small"
-                    @click="handleAddParticipant(scope.row)"
-                    v-hasPermi="['system:gameEvent:addParticipant']"
-                  ></el-button>
-                </el-tooltip>
-                <el-tooltip content="添加裁判" placement="top">
-                  <el-button
-                    link
-                    type="primary"
-                    icon="Avatar"
-                    size="small"
-                    @click="handleAddReferee(scope.row)"
-                    v-hasPermi="['system:gameEvent:addReferee']"
-                  ></el-button>
-                </el-tooltip>
-              </div>
-
-              <!-- 第三行:文章操作 -->
-              <div class="button-row">
-                <el-tooltip content="编写文章" placement="top">
-                  <el-button
-                    link
-                    type="warning"
-                    icon="EditPen"
-                    size="small"
-                    @click="handleWriteArticle(scope.row)"
-                    v-hasPermi="['system:gameEvent:writeArticle']"
-                  ></el-button>
-                </el-tooltip>
-              </div>
-            </div>
+            <el-tooltip content="修改" placement="top">
+              <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:gameEvent:edit']">
+                修改
+              </el-button>
+            </el-tooltip>
           </template>
         </el-table-column>
-
-        <el-table-column label="主键" align="center" prop="eventId" v-if="columns[0].visible" />
+        <el-table-column label="赛事id" align="center" prop="eventId" v-if="columns[0].visible" />
         <el-table-column label="赛事编号" align="center" prop="eventCode" v-if="columns[1].visible" />
         <el-table-column label="赛事名称" align="center" prop="eventName" v-if="columns[2].visible" />
         <el-table-column label="赛事类型" align="center" prop="eventType" v-if="columns[3].visible">
@@ -417,7 +363,7 @@ const total = ref(0);
 
 // 列显隐数据
 const columns = ref<FieldOption[]>([
-  { key: 0, label: '主键', visible: false },
+  { key: 0, label: '赛事id', visible: false },
   { key: 1, label: '赛事编号', visible: true },
   { key: 2, label: '赛事名称', visible: true },
   { key: 3, label: '赛事类型', visible: true },
@@ -913,6 +859,77 @@ const handleSaveArticle = async () => {
   }
 };
 
+// 基于默认赛事的操作函数
+/** 下载模板(默认赛事) */
+const handleDownloadTemplateDefault = async () => {
+  const defaultEvent = gameEventStore.defaultEventInfo;
+  if (!defaultEvent) {
+    proxy?.$modal.msgError('请先设置默认赛事');
+    return;
+  }
+  handleDownloadTemplate(defaultEvent);
+};
+
+/** 导入报名信息(默认赛事) */
+const handleImportRegistrationDefault = async () => {
+  const defaultEvent = gameEventStore.defaultEventInfo;
+  if (!defaultEvent) {
+    proxy?.$modal.msgError('请先设置默认赛事');
+    return;
+  }
+  handleImportRegistration(defaultEvent);
+};
+
+/** 添加参赛者(默认赛事) */
+const handleAddParticipantDefault = async () => {
+  const defaultEvent = gameEventStore.defaultEventInfo;
+  if (!defaultEvent) {
+    proxy?.$modal.msgError('请先设置默认赛事');
+    return;
+  }
+  handleAddParticipant(defaultEvent);
+};
+
+/** 添加裁判(默认赛事) */
+const handleAddRefereeDefault = async () => {
+  const defaultEvent = gameEventStore.defaultEventInfo;
+  if (!defaultEvent) {
+    proxy?.$modal.msgError('请先设置默认赛事');
+    return;
+  }
+  handleAddReferee(defaultEvent);
+};
+
+/** 预览(默认赛事) */
+const handlePreviewDefault = async () => {
+  const defaultEvent = gameEventStore.defaultEventInfo;
+  if (!defaultEvent) {
+    proxy?.$modal.msgError('请先设置默认赛事');
+    return;
+  }
+  handlePreview(defaultEvent);
+};
+
+/** 比赛数据(默认赛事) */
+const handleGameDataDefault = async () => {
+  const defaultEvent = gameEventStore.defaultEventInfo;
+  if (!defaultEvent) {
+    proxy?.$modal.msgError('请先设置默认赛事');
+    return;
+  }
+  handleGameData(defaultEvent);
+};
+
+/** 编写文章(默认赛事) */
+const handleWriteArticleDefault = async () => {
+  const defaultEvent = gameEventStore.defaultEventInfo;
+  if (!defaultEvent) {
+    proxy?.$modal.msgError('请先设置默认赛事');
+    return;
+  }
+  handleWriteArticle(defaultEvent);
+};
+
 onMounted(() => {
   // 获取默认赛事信息
   gameEventStore.fetchDefaultEvent();

+ 451 - 0
src/views/system/gameEventGroup/detail.vue

@@ -0,0 +1,451 @@
+<template>
+  <div class="p-4">
+    <!-- 顶部信息区域 -->
+    <el-card shadow="hover" class="mb-4">
+      <div class="flex justify-between items-center">
+        <div class="text-left">
+          <h2 class="text-xl font-bold text-gray-800 mb-2">{{ projectName }} - {{ groupInfo.groupName }}</h2>
+          <div class="grid grid-cols-3 gap-4 text-sm text-gray-600">
+            <div><span class="font-medium"></span>{{ groupInfo.personNum }}人</div>
+            <div><span class="font-medium">组数:</span>{{ groupInfo.includeGroupNum }}组</div>
+            <div><span class="font-medium">道数:</span>{{ groupInfo.trackNum }}道</div>
+            <div><span class="font-medium">开始时间:</span>{{ groupInfo.beginTime }}</div>
+            <div><span class="font-medium">预计结束时间:</span>{{ groupInfo.endTime }}</div>
+            <div><span class="font-medium">场地数量:</span>{{ groupInfo.fieldNum }}个</div>
+          </div>
+        </div>
+        <div class="text-right">
+          <el-button type="primary" @click="generateGroups" :loading="generating">重新生成分组</el-button>
+          <el-button @click="goBack">返回</el-button>
+        </div>
+      </div>
+    </el-card>
+
+    <!-- 分组详情表格 -->
+    <el-card shadow="hover">
+      <template #header>
+        <div class="flex justify-between items-center">
+          <span class="font-medium">分组详情</span>
+          <div class="text-sm text-gray-500">
+            共 {{ groupInfo.includeGroupNum }} 组,{{ groupInfo.trackNum }} 条道
+          </div>
+        </div>
+      </template>
+
+      <div class="overflow-x-auto">
+        <table class="w-full border-collapse border border-gray-300">
+          <!-- 表头 -->
+          <thead>
+            <tr class="bg-gray-100">
+              <th class="border border-gray-300 px-4 py-2 text-center font-medium">组别</th>
+              <th 
+                v-for="track in groupInfo.trackNum" 
+                :key="track" 
+                class="border border-gray-300 px-4 py-2 text-center font-medium"
+              >
+                第{{ getTrackName(track) }}道
+              </th>
+            </tr>
+          </thead>
+          
+          <!-- 分组内容 -->
+          <tbody>
+            <tr 
+              v-for="groupIndex in groupInfo.includeGroupNum" 
+              :key="groupIndex"
+              class="hover:bg-gray-50"
+            >
+              <td class="border border-gray-300 px-4 py-3 text-center font-medium bg-blue-50">
+                第{{ groupIndex }}组
+              </td>
+              <td 
+                v-for="track in groupInfo.trackNum" 
+                :key="track" 
+                class="border border-gray-300 px-4 py-3 text-center"
+              >
+                 <div v-if="getAthleteByGroupAndTrack(groupIndex, track)" class="space-y-1">
+                   <div class="font-medium text-blue-600">{{ getAthleteByGroupAndTrack(groupIndex, track)?.athleteCode }}</div>
+                   <div class="text-sm">{{ getAthleteByGroupAndTrack(groupIndex, track)?.name }}</div>
+                   <div class="text-xs text-gray-500">{{ getTeamName(getAthleteByGroupAndTrack(groupIndex, track)?.teamId) }}</div>
+                 </div>
+                <div v-else class="text-gray-400 text-sm">-</div>
+              </td>
+            </tr>
+          </tbody>
+        </table>
+      </div>
+    </el-card>
+
+    <!-- 统计信息 -->
+    <el-card shadow="hover" class="mt-4">
+      <template #header>
+        <span class="font-medium">分组统计</span>
+      </template>
+      
+      <div class="grid grid-cols-2 md:grid-cols-4 gap-4">
+        <div class="text-center p-3 bg-blue-50 rounded-lg">
+          <div class="text-2xl font-bold text-blue-600">{{ totalAthletes }}</div>
+          <div class="text-sm text-gray-600">符合条件的运动员数量</div>
+        </div>
+        <div class="text-center p-3 bg-green-50 rounded-lg">
+          <div class="text-2xl font-bold text-green-600">{{ groupInfo.includeGroupNum }}</div>
+          <div class="text-sm text-gray-600">分组数</div>
+        </div>
+        <div class="text-center p-3 bg-purple-50 rounded-lg">
+          <div class="text-2xl font-bold text-purple-600">{{ groupInfo.trackNum }}</div>
+          <div class="text-sm text-gray-600">道数</div>
+        </div>
+        <div class="text-center p-3 bg-orange-50 rounded-lg">
+          <div class="text-2xl font-bold text-orange-600">{{ groupInfo.personNum }}</div>
+          <div class="text-sm text-gray-600">{{ groupInfo.groupName }}人数</div>
+        </div>
+      </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 { 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 { 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();
+const router = useRouter();
+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 loading = ref(false);
+// 生成分组状态
+const generating = ref(false);
+// 项目名称(需要从项目信息中获取)
+const projectName = computed(() => {
+  if (!groupInfo.value.projectId) return '';
+  const project = projects.value.find(p => p.projectId === groupInfo.value.projectId);
+  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 getTrackName = (track: number) => {
+  const trackNames = ['一', '二', '三', '四', '五', '六', '七', '八','九','十'];
+  return trackNames[track - 1] || track;
+};
+
+// 根据组别和道次获取运动员
+const getAthleteByGroupAndTrack = (groupIndex: number, track: number) => {
+  const key = `${groupIndex}-${track}`;
+  return groupResult.value.get(key);
+};
+
+// 根据队伍ID获取队伍名称
+const getTeamName = (teamId: string | number | undefined) => {
+  if (!teamId) return '';
+  const team = teams.value.find(t => t.teamId === teamId);
+  return team?.teamName || '';
+};
+
+// 获取分组信息
+const getGroupInfo = async () => {
+  try {
+    loading.value = true;
+    const groupId = route.query.id;
+    if (!groupId || Array.isArray(groupId)) {
+      proxy?.$modal.msgError('分组ID不能为空');
+      return;
+    }
+    
+    const res = await getGameEventGroup(groupId);
+    groupInfo.value = res.data;
+    
+    // 获取运动员、队伍和项目信息
+    await Promise.all([
+      getAthletes(),
+      getTeams(),
+      getProjects()
+    ]);
+    
+    // 生成分组
+    generateGroups();
+  } catch (error) {
+    console.error('获取分组信息失败:', error);
+    proxy?.$modal.msgError('获取分组信息失败');
+  } finally {
+    loading.value = false;
+  }
+};
+
+// 获取运动员列表
+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 () => {
+  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;
+  } catch (error) {
+    console.error('获取项目列表失败:', error);
+  }
+};
+
+// 生成分组
+const generateGroups = async () => {
+  try {
+    generating.value = true;
+    
+    // 清空之前的分组结果
+    groupResult.value.clear();
+    
+    // 筛选符合条件的运动员
+    const eligibleAthletes = 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;
+    });
+    
+    if (eligibleAthletes.length === 0) {
+      proxy?.$modal.msgWarning('没有找到符合条件的运动员');
+      return;
+    }
+    
+    // 随机打乱运动员顺序
+    const shuffledAthletes = [...eligibleAthletes].sort(() => Math.random() - 0.5);
+    
+    // 按组别和道次分配运动员
+    let athleteIndex = 0;
+    
+    for (let groupIndex = 1; groupIndex <= groupInfo.value.includeGroupNum; groupIndex++) {
+      for (let track = 1; track <= groupInfo.value.trackNum; track++) {
+        if (athleteIndex < shuffledAthletes.length) {
+           let selectedAthlete = shuffledAthletes[athleteIndex];
+           
+           // 检查同一组中是否已有同一队伍的运动员
+           const hasSameTeamInGroup = Array.from(groupResult.value.entries())
+             .some(([key, existingAthlete]) => {
+               const [existingGroup] = key.split('-');
+               return existingGroup === groupIndex.toString() && 
+                      existingAthlete.teamId === selectedAthlete.teamId;
+             });
+           
+           // 如果同一组中已有同一队伍的运动员,尝试找下一个不同队伍的运动员
+           if (hasSameTeamInGroup) {
+             let nextAthleteIndex = athleteIndex + 1;
+             let found = false;
+             
+             while (nextAthleteIndex < shuffledAthletes.length && !found) {
+               const nextAthlete = shuffledAthletes[nextAthleteIndex];
+               const hasSameTeam = Array.from(groupResult.value.entries())
+                 .some(([key, existingAthlete]) => {
+                   const [existingGroup] = key.split('-');
+                   return existingGroup === groupIndex.toString() && 
+                          existingAthlete.teamId === nextAthlete.teamId;
+                 });
+               
+               if (!hasSameTeam) {
+                 selectedAthlete = nextAthlete;
+                 found = true;
+               }
+               nextAthleteIndex++;
+             }
+           }
+           
+           const key = `${groupIndex}-${track}`;
+           groupResult.value.set(key, selectedAthlete);
+           athleteIndex++;
+         }
+      }
+    }
+    
+    proxy?.$modal.msgSuccess('分组生成成功');
+  } catch (error) {
+    console.error('生成分组失败:', error);
+    proxy?.$modal.msgError('生成分组失败');
+  } finally {
+    generating.value = false;
+  }
+};
+
+// 返回上一页
+const goBack = () => {
+  router.go(-1);
+};
+
+onMounted(() => {
+  getGroupInfo();
+});
+</script>
+
+<style scoped>
+.overflow-x-auto {
+  overflow-x: auto;
+}
+
+/* 响应式表格 */
+@media (max-width: 768px) {
+  .grid {
+    grid-template-columns: repeat(1, 1fr);
+  }
+  
+  .overflow-x-auto {
+    font-size: 12px;
+  }
+  
+  .px-4 {
+    padding-left: 8px;
+    padding-right: 8px;
+  }
+  
+  .py-3 {
+    padding-top: 6px;
+    padding-bottom: 6px;
+  }
+}
+</style> 

+ 335 - 75
src/views/system/gameEventGroup/index.vue

@@ -4,18 +4,29 @@
       <div v-show="showSearch" class="mb-[10px]">
         <el-card shadow="hover">
           <el-form ref="queryFormRef" :model="queryParams" :inline="true">
-            <el-form-item label="赛事组别" prop="groupName">
-              <el-input v-model="queryParams.groupName" placeholder="请输入组名" clearable @keyup.enter="handleQuery" />
+            <el-form-item label="项目类型" prop="projectTypeFilter">
+              <el-select v-model="projectTypeFilter" placeholder="请选择项目类型" clearable @change="handleProjectTypeFilterChange">
+                <el-option
+                  v-for="dict in game_project_type"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                />
+              </el-select>
             </el-form-item>
-            <!-- <el-form-item label="包含项目列表" prop="projectList">
-              <el-input v-model="queryParams.projectList" placeholder="请输入包含项目列表" clearable @keyup.enter="handleQuery" />
-            </el-form-item> -->
-            <!-- <el-form-item label="排序字段" prop="sortOrder">
-              <el-input v-model="queryParams.sortOrder" placeholder="请输入排序字段" clearable @keyup.enter="handleQuery" />
+            <el-form-item label="项目" prop="projectId">
+              <el-select v-model="queryParams.projectId" placeholder="请选择项目" clearable>
+                <el-option
+                  v-for="project in filteredProjectList"
+                  :key="project.projectId"
+                  :label="project.projectName"
+                  :value="project.projectId"
+                />
+              </el-select>
+            </el-form-item>
+            <el-form-item label="组别" prop="groupName">
+              <el-input v-model="queryParams.groupName" placeholder="请输入组别名称" clearable @keyup.enter="handleQuery" />
             </el-form-item>
-            <el-form-item label="排序规则(0升序1降序)" prop="sortRule">
-              <el-input v-model="queryParams.sortRule" placeholder="请输入排序规则(0升序1降序)" clearable @keyup.enter="handleQuery" />
-            </el-form-item> -->
             <el-form-item>
               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
               <el-button icon="Refresh" @click="resetQuery">重置</el-button>
@@ -50,17 +61,38 @@
 
       <el-table v-loading="loading" border :data="gameEventGroupList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="主键" align="center" prop="groupId" v-if="columns[0].visible" />
-        <!-- <el-table-column label="赛事ID" align="center" prop="eventId" /> -->
-        <el-table-column label="组别" align="center" prop="groupName" v-if="columns[1].visible" />
-        <el-table-column label="包含项目" align="center" prop="projectList" v-if="columns[2].visible" />
-        <el-table-column label="成员性别" align="center" prop="memberGender" v-if="columns[3].visible">
+        <el-table-column label="组别id" align="center" prop="groupId" v-if="columns[0].visible" />
+        <el-table-column label="项目类型" align="center" v-if="columns[1].visible">
+          <template #default="scope">
+            <dict-tag :options="game_project_type" :value="getProjectTypeByProjectId(scope.row.projectId) || ''" />
+          </template>
+        </el-table-column>
+        <el-table-column label="项目" align="center" v-if="columns[2].visible">
           <template #default="scope">
-            {{ genderMap[scope.row.memberGender] || '未知' }}
+            {{ getProjectNameByProjectId(scope.row.projectId) }}
+          </template>
+        </el-table-column>
+        <el-table-column label="组别" align="center" prop="groupName" v-if="columns[3].visible" />
+        <el-table-column label="人/组" align="center" prop="personNum" v-if="columns[4].visible" />
+        <el-table-column label="组数" align="center" prop="includeGroupNum" v-if="columns[5].visible" />
+        <el-table-column label="道数" align="center" prop="trackNum" v-if="columns[6].visible" />
+        <el-table-column label="场地数量" align="center" prop="fieldNum" v-if="columns[7].visible" />
+        <el-table-column label="每组用时(分钟)" align="center" prop="duration" v-if="columns[8].visible" />
+        <el-table-column label="比赛时间" align="center" v-if="columns[9].visible">
+          <template #default="scope">
+            {{ scope.row.beginTime }} - {{ scope.row.endTime }}
+          </template>
+        </el-table-column>
+        <el-table-column label="成员性别" align="center" prop="memberGender" v-if="columns[10].visible">
+          <template #default="scope">
+            <dict-tag :options="sys_user_sex" :value="scope.row.memberGender" />
           </template>
         </el-table-column>
         <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
           <template #default="scope">
+            <el-tooltip content="分组" placement="top">
+              <el-button link type="success" icon="Grid" @click="handleGroup(scope.row)" v-hasPermi="['system:gameEventGroup:edit']"></el-button>
+            </el-tooltip>
             <el-tooltip content="修改" placement="top">
               <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:gameEventGroup:edit']"></el-button>
             </el-tooltip>
@@ -73,31 +105,125 @@
 
       <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="getList" />
     </el-card>
+
     <!-- 添加或修改赛事分组对话框 -->
-    <el-dialog :title="dialog.title" v-model="dialog.visible" width="800px" append-to-body>
-      <el-form ref="gameEventGroupFormRef" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="组名" prop="groupName">
-          <el-input v-model="form.groupName" placeholder="请输入组名" />
-        </el-form-item>
-        <el-form-item label="包含项目" prop="projectList">
-          <el-transfer
-            v-model="form.selectedProjects"
-            :data="gameEventProjectList"
-            :titles="['可选项目', '已选项目']"
-            :button-texts="['移除', '添加']"
-            filterable
-            style="width: 100%"
-          />
-        </el-form-item>
-        <el-form-item label="成员性别" prop="memberGender">
-          <el-select v-model="form.memberGender" placeholder="请选择性别">
-            <el-option label="不分男女" value="0"></el-option>
-            <el-option label="男" value="1"></el-option>
-            <el-option label="女" value="2"></el-option>
-          </el-select>
-        </el-form-item>
+    <el-dialog :title="dialog.title" v-model="dialog.visible" width="900px" append-to-body>
+      <el-form ref="gameEventGroupFormRef" :model="form" :rules="rules" label-width="120px">
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="项目类型" prop="projectTypeFilter">
+              <el-select 
+                v-model="formProjectTypeFilter" 
+                placeholder="请选择项目类型" 
+                style="width: 100%"
+                @change="handleFormProjectTypeFilterChange"
+                :disabled="!!form.groupId"
+              >
+                <el-option
+                  v-for="dict in game_project_type"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="项目" prop="projectId">
+              <el-select 
+                v-model="form.projectId" 
+                placeholder="请选择项目" 
+                style="width: 100%"
+                @change="handleFormProjectChange"
+                :disabled="!formProjectTypeFilter || !!form.groupId"
+              >
+                <el-option
+                  v-for="project in filteredFormProjectList"
+                  :key="project.projectId"
+                  :label="project.projectName"
+                  :value="project.projectId"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="组别名称" prop="groupName">
+              <el-input v-model="form.groupName" placeholder="请输入组别名称" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="成员性别" prop="memberGender">
+              <el-select v-model="form.memberGender" placeholder="请选择性别" style="width: 100%">
+                <el-option
+                  v-for="dict in sys_user_sex"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                />
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="人/组" prop="personNum">
+              <el-input-number v-model="form.personNum" :min="1" placeholder="请输入每组人数" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="组数" prop="includeGroupNum">
+              <el-input-number v-model="form.includeGroupNum" :min="1" placeholder="请输入组数" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="道数" prop="trackNum">
+              <el-input-number v-model="form.trackNum" :min="1" placeholder="请输入道数" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="场地数量" prop="fieldNum">
+              <el-input-number v-model="form.fieldNum" :min="1" placeholder="请输入场地数量" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="每组用时(分钟)" prop="duration">
+              <el-input-number v-model="form.duration" :min="1" placeholder="请输入每组用时" style="width: 100%" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="组别开始时间" prop="beginTime">
+              <el-time-picker
+                v-model="form.beginTime"
+                placeholder="选择开始时间"
+                format="HH:mm"
+                value-format="HH:mm"
+                style="width: 100%"
+                :disabled="!form.projectId"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
+        <el-row :gutter="20">
+          <el-col :span="12">
+            <el-form-item label="预计结束时间" prop="endTime">
+              <el-input v-model="calculatedEndTime" placeholder="自动计算" disabled style="width: 100%" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+
         <el-form-item label="备注" prop="remark">
-          <el-input v-model="form.remark" type="textarea" placeholder="请输入内容" />
+          <el-input v-model="form.remark" type="textarea" placeholder="请输入备注内容" />
         </el-form-item>
       </el-form>
       <template #footer>
@@ -111,22 +237,21 @@
 </template>
 
 <script setup name="GameEventGroup" lang="ts">
-import { nextTick, ref, onMounted } from 'vue';
+import { nextTick, ref, onMounted, computed } from 'vue';
+import { useRouter } from 'vue-router';
 import { listGameEventGroup, getGameEventGroup, delGameEventGroup, addGameEventGroup, updateGameEventGroup } from '@/api/system/gameEventGroup';
 import { listGameEventProject } from '@/api/system/gameEventProject';
 import { GameEventGroupVO, GameEventGroupQuery, GameEventGroupForm } from '@/api/system/gameEventGroup/types';
+import { GameEventProjectVO } from '@/api/system/gameEventProject/types';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+const router = useRouter();
 
-// 性别映射
-const genderMap = {
-  '0': '不分男女',
-  '1': '男',
-  '2': '女'
-};
+// 字典数据
+const { game_project_type, sys_user_sex } = toRefs<any>(proxy?.useDict('game_project_type', 'sys_user_sex'));
 
 const gameEventGroupList = ref<GameEventGroupVO[]>([]);
-const gameEventProjectList = ref<Array<{ key: string; label: string }>>([]); // 赛事项目列表(用于穿梭框)
+const projectList = ref<GameEventProjectVO[]>([]);
 const buttonLoading = ref(false);
 const loading = ref(true);
 const showSearch = ref(true);
@@ -135,12 +260,23 @@ const single = ref(true);
 const multiple = ref(true);
 const total = ref(0);
 
+// 项目类型过滤器(用于查询和表单,不存储在数据中)
+const projectTypeFilter = ref<string>('');
+const formProjectTypeFilter = ref<string>('');
+
 // 列显隐数据
 const columns = ref<FieldOption[]>([
-  { key: 0, label: '主键', visible: false },
-  { key: 1, label: '赛事组别', visible: true },
-  { key: 2, label: '包含项目', visible: true },
-  { key: 3, label: '成员性别', visible: true },
+  { key: 0, label: '组别id', visible: false },
+  { key: 1, label: '项目类型', visible: true },
+  { key: 2, label: '项目', visible: true },
+  { key: 3, label: '组别', visible: true },
+  { key: 4, label: '人/组', visible: true },
+  { key: 5, label: '组数', visible: true },
+  { key: 6, label: '道数', visible: true },
+  { key: 7, label: '场地数量', visible: true },
+  { key: 8, label: '每组用时(分钟)', visible: true },
+  { key: 9, label: '比赛时间', visible: true },
+  { key: 10, label: '成员性别', visible: true },
 ]);
 
 const queryFormRef = ref<ElFormInstance>();
@@ -156,29 +292,86 @@ const initFormData: GameEventGroupForm = {
   eventId: undefined,
   groupName: undefined,
   projectList: undefined,
-  selectedProjects: [], // 添加已选项目列表
+  selectedProjects: [],
   memberGender: undefined,
   sortOrder: undefined,
   sortRule: undefined,
   status: undefined,
-  remark: undefined
+  remark: undefined,
+  includeGroupNum: undefined,
+  projectId: undefined,
+  personNum: undefined,
+  beginTime: undefined,
+  endTime: undefined,
+  trackNum: undefined,
+  fieldNum: undefined,
+  duration: undefined
 };
+
 const data = reactive<PageData<GameEventGroupForm, GameEventGroupQuery>>({
   form: { ...initFormData },
   queryParams: {
     pageNum: 1,
     pageSize: 10,
-    orderByColumn: '',
-    isAsc: ''
+    orderByColumn: undefined,
+    isAsc: undefined,
+    projectId: undefined,
+    groupName: undefined
   },
   rules: {
-    groupName: [{ required: true, message: '项目组名称不能为空', trigger: 'blur' }],
-    memberGender: [{ required: true, message: '成员性别不能为空', trigger: 'change' }]
+    projectId: [{ required: true, message: '请选择项目', trigger: 'change' }],
+    groupName: [{ required: true, message: '组别名称不能为空', trigger: 'blur' }],
+    memberGender: [{ required: true, message: '成员性别不能为空', trigger: 'change' }],
+    personNum: [{ required: true, message: '每组人数不能为空', trigger: 'blur' }],
+    includeGroupNum: [{ required: true, message: '组数不能为空', trigger: 'blur' }],
+    trackNum: [{ required: true, message: '道数不能为空', trigger: 'blur' }],
+    fieldNum: [{ required: true, message: '场地数量不能为空', trigger: 'blur' }],
+    duration: [{ required: true, message: '每组用时不能为空', trigger: 'blur' }],
+    beginTime: [{ required: true, message: '开始时间不能为空', trigger: 'change' }]
   }
 });
 
 const { queryParams, form, rules } = toRefs(data);
 
+// 过滤后的项目列表(用于查询)
+const filteredProjectList = computed(() => {
+  if (!projectTypeFilter.value) return projectList.value;
+  return projectList.value.filter(project => project.projectType === projectTypeFilter.value);
+});
+
+// 过滤后的项目列表(用于表单)
+const filteredFormProjectList = computed(() => {
+  if (!formProjectTypeFilter.value) return [];
+  return projectList.value.filter(project => project.projectType === formProjectTypeFilter.value);
+});
+
+// 根据项目ID获取项目类型
+const getProjectTypeByProjectId = (projectId: string | number) => {
+  if (!projectId) return '';
+  const project = projectList.value.find(p => p.projectId === projectId);
+  return project?.projectType || '';
+};
+
+// 根据项目ID获取项目名称
+const getProjectNameByProjectId = (projectId: string | number) => {
+  if (!projectId) return '';
+  const project = projectList.value.find(p => p.projectId === projectId);
+  return project?.projectName || '';
+};
+
+// 计算预计结束时间
+const calculatedEndTime = computed(() => {
+  if (!form.value.beginTime || !form.value.duration || !form.value.includeGroupNum) {
+    return '';
+  }
+  
+  const beginTime = new Date(`2000-01-01 ${form.value.beginTime}`);
+  const totalMinutes = form.value.duration * form.value.includeGroupNum;
+  const endTime = new Date(beginTime.getTime() + totalMinutes * 60 * 1000);
+  
+  return endTime.toTimeString().slice(0, 5); // 返回 HH:mm 格式
+});
+
 /** 查询赛事分组列表 */
 const getList = async () => {
   loading.value = true;
@@ -196,10 +389,33 @@ const getProjectList = async () => {
     orderByColumn: '',
     isAsc: ''
   });
-  gameEventProjectList.value = res.rows.map((item) => ({
-    key: String(item.projectId),
-    label: `${item.projectName}`
-  }));
+  projectList.value = res.rows;
+};
+
+// 查询条件中项目类型变化
+const handleProjectTypeFilterChange = () => {
+  queryParams.value.projectId = undefined;
+};
+
+// 表单中项目类型变化
+const handleFormProjectTypeFilterChange = () => {
+  form.value.projectId = undefined;
+  form.value.beginTime = undefined;
+  form.value.endTime = undefined;
+  form.value.trackNum = undefined;
+  form.value.fieldNum = undefined;
+  form.value.duration = undefined;
+};
+
+// 表单中项目变化
+const handleFormProjectChange = () => {
+  if (form.value.projectId) {
+    const selectedProject = projectList.value.find(p => p.projectId === form.value.projectId);
+    if (selectedProject) {
+      // 可以在这里设置一些默认值或者进行其他处理
+      console.log('选中的项目:', selectedProject);
+    }
+  }
 };
 
 /** 取消按钮 */
@@ -211,6 +427,7 @@ const cancel = () => {
 /** 表单重置 */
 const reset = () => {
   form.value = { ...initFormData };
+  formProjectTypeFilter.value = '';
   gameEventGroupFormRef.value?.resetFields();
 };
 
@@ -223,6 +440,7 @@ const handleQuery = () => {
 /** 重置按钮操作 */
 const resetQuery = () => {
   queryFormRef.value?.resetFields();
+  projectTypeFilter.value = '';
   handleQuery();
 };
 
@@ -251,11 +469,12 @@ const handleUpdate = async (row?: GameEventGroupVO) => {
   const res = await getGameEventGroup(_groupId);
   Object.assign(form.value, res.data);
 
-  // 处理项目列表,将逗号分隔的字符串转换为数组
-  if (res.data.projectList) {
-    form.value.selectedProjects = res.data.projectList.split(',');
-  } else {
-    form.value.selectedProjects = [];
+  // 根据项目ID设置项目类型过滤器
+  if (res.data.projectId) {
+    const project = projectList.value.find(p => p.projectId === res.data.projectId);
+    if (project) {
+      formProjectTypeFilter.value = project.projectType;
+    }
   }
 
   dialog.visible = true;
@@ -270,17 +489,52 @@ const handleUpdate = async (row?: GameEventGroupVO) => {
 const submitForm = () => {
   gameEventGroupFormRef.value?.validate(async (valid: boolean) => {
     if (valid) {
-      buttonLoading.value = true;
-      // 处理项目列表数据,将数组转换为逗号分隔的字符串
-      const submitForm = { ...form.value };
-      if (submitForm.selectedProjects && submitForm.selectedProjects.length > 0) {
-        submitForm.projectList = submitForm.selectedProjects.join(',');
-      } else {
-        submitForm.projectList = '';
+      // 校验组数和道数的关系
+      if (form.value.includeGroupNum && form.value.trackNum && form.value.personNum) {
+        const totalCapacity = form.value.includeGroupNum * form.value.trackNum;
+        if (totalCapacity < form.value.personNum) {
+          const recommendedGroupNum = Math.ceil(form.value.personNum / form.value.trackNum);
+          proxy?.$modal.msgError(`组数过小请重新输入,推荐组数:${recommendedGroupNum}`);
+          return;
+        }
+      }
+
+      // 自动计算结束时间
+      if (form.value.beginTime && form.value.duration && form.value.includeGroupNum) {
+        const beginTime = new Date(`2000-01-01 ${form.value.beginTime}`);
+        const totalMinutes = form.value.duration * form.value.includeGroupNum;
+        const endTime = new Date(beginTime.getTime() + totalMinutes * 60 * 1000);
+        form.value.endTime = endTime.toTimeString().slice(0, 5);
+      }
+
+      // 验证时间范围
+      if (form.value.beginTime && form.value.endTime) {
+        const beginTime = new Date(`2000-01-01 ${form.value.beginTime}`);
+        const endTime = new Date(`2000-01-01 ${form.value.endTime}`);
+        
+        if (beginTime >= endTime) {
+          proxy?.$modal.msgError('组别结束时间必须晚于开始时间');
+          return;
+        }
+        
+        // 验证组别时间是否在项目时间范围内
+        if (form.value.projectId) {
+          const selectedProject = projectList.value.find(p => p.projectId === form.value.projectId);
+          if (selectedProject && selectedProject.startTime && selectedProject.endTime) {
+            const projectStart = new Date(`2000-01-01 ${selectedProject.startTime}`);
+            const projectEnd = new Date(`2000-01-01 ${selectedProject.endTime}`);
+            
+            if (beginTime < projectStart || endTime > projectEnd) {
+              proxy?.$modal.msgError('组别比赛时间必须在项目比赛时间范围内');
+              return;
+            }
+          }
+        }
       }
-      // 删除selectedProjects属性,因为它不需要提交到后端
-      delete submitForm.selectedProjects;
 
+      buttonLoading.value = true;
+      const submitForm = { ...form.value };
+      
       if (form.value.groupId) {
         await updateGameEventGroup(submitForm).finally(() => (buttonLoading.value = false));
       } else {
@@ -313,7 +567,13 @@ const handleExport = () => {
   );
 };
 
+/** 分组按钮操作 */
+const handleGroup = (row: GameEventGroupVO) => {
+  router.push({ path: '/system/gameEventGroup/detail', query: { id: row.groupId } });
+};
+
 onMounted(() => {
   getList();
+  getProjectList();
 });
 </script>

+ 3 - 3
src/views/system/gameEventProject/index.vue

@@ -7,11 +7,11 @@
             <el-form-item label="项目名称" prop="projectName">
               <el-input v-model="queryParams.projectName" placeholder="请输入项目名称" clearable @keyup.enter="handleQuery" />
             </el-form-item>
-            <el-form-item label="项目组别" prop="groupType">
+            <!-- <el-form-item label="项目组别" prop="groupType">
               <el-select v-model="queryParams.groupType" placeholder="请选择项目组别" clearable @change="handleQuery">
                 <el-option v-for="group in gameEventGroupList" :key="group.groupName" :label="group.groupName" :value="group.groupName" />
               </el-select>
-            </el-form-item>
+            </el-form-item> -->
             <el-form-item>
               <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
               <el-button icon="Refresh" @click="resetQuery">重置</el-button>
@@ -53,7 +53,7 @@
             <dict-tag :options="game_project_type" :value="scope.row.projectType || ''" />
           </template>
         </el-table-column>
-        <el-table-column label="项目组别" align="center" prop="groupType" v-if="columns[3].visible" />
+        <!-- <el-table-column label="项目组别" align="center" prop="groupType" v-if="columns[3].visible" /> -->
         <el-table-column label="比赛场地" align="center" prop="location" v-if="columns[4].visible" />
         <el-table-column label="计算规则" align="center" prop="scoreRule" v-if="columns[5].visible">
           <template #default="scope">

+ 15 - 15
src/views/system/gameTeam/index.vue

@@ -78,11 +78,11 @@
     <!-- 添加或修改参赛队伍对话框 -->
     <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
       <el-form ref="gameTeamFormRef" :model="form" :rules="rules" label-width="80px">
-        <el-form-item label="赛事" prop="eventId">
+        <!-- <el-form-item label="赛事" prop="eventId">
           <el-select v-model="form.eventId" placeholder="请选择赛事" clearable filterable style="width: 100%">
             <el-option v-for="option in eventOptions" :key="option.value" :label="option.label" :value="option.value" />
           </el-select>
-        </el-form-item>
+        </el-form-item> -->
         <el-form-item label="队伍名称" prop="teamName">
           <el-input v-model="form.teamName" placeholder="请输入队伍名称" />
         </el-form-item>
@@ -166,7 +166,7 @@ const eventOptions = ref<Array<{ label: string; value: string | number }>>([]);
 const columns = ref<FieldOption[]>([
   { key: 0, label: '主键', visible: false },
   { key: 1, label: '队伍编号', visible: true },
-  { key: 2, label: '赛事名称', visible: true },
+  { key: 2, label: '赛事名称', visible: false },
   { key: 3, label: '队伍名称', visible: true },
   { key: 4, label: '团队描述', visible: true },
   { key: 5, label: '领队', visible: false },
@@ -279,17 +279,17 @@ const getList = async () => {
 };
 
 /** 获取赛事选项列表 */
-const getEventOptions = async () => {
-  try {
-    const res = await getEventIdNameMap();
-    eventOptions.value = Object.entries(res.data).map(([key, value]) => ({
-      label: key as string,
-      value: value as string | number
-    }));
-  } catch (error) {
-    console.error('获取赛事列表失败:', error);
-  }
-};
+// const getEventOptions = async () => {
+//   try {
+//     const res = await getEventIdNameMap();
+//     eventOptions.value = Object.entries(res.data).map(([key, value]) => ({
+//       label: key as string,
+//       value: value as string | number
+//     }));
+//   } catch (error) {
+//     console.error('获取赛事列表失败:', error);
+//   }
+// };
 
 /** 取消按钮 */
 const cancel = () => {
@@ -412,6 +412,6 @@ const importTemplate = () => {
 
 onMounted(() => {
   getList();
-  getEventOptions();
+  // getEventOptions();
 });
 </script>