Quellcode durchsuchen

feat(system): 优化裁判与项目关联逻辑

- 移除 GameAthlete 类型中的 number 字段
- 更新 GameEventProject 类型,将 refereeId 改为 refereeGroups
- 新增裁判组查看对话框组件
- 实现裁判添加、更新和删除时对项目表中裁判组的同步更新
- 优化项目列表展示,增加裁判组查看功能
zhou vor 2 Wochen
Ursprung
Commit
94957ea4a7

+ 0 - 10
src/api/system/gameAthlete/types.ts

@@ -69,11 +69,6 @@ export interface GameAthleteVO {
    */
   groupType: string;
 
-  /**
-   * 号码
-   */
-  number: string;
-
   /**
    * 参与项目列表
    */
@@ -166,11 +161,6 @@ export interface GameAthleteForm extends BaseEntity {
    */
   groupType?: string;
 
-  /**
-   * 号码
-   */
-  number?: string;
-
   /**
    * 参与项目列表
    */

+ 7 - 8
src/api/system/gameEventProject/types.ts

@@ -14,7 +14,7 @@ export interface GameEventProjectVO {
   projectName: string;
 
   /**
-   * 项目类型(个人/团体)
+   * 项目类型
    */
   projectType: string;
 
@@ -24,10 +24,9 @@ export interface GameEventProjectVO {
   groupType: string;
 
   /**
-   * 裁判员ID
+   * 裁判
    */
-  refereeId: string | number;
-
+  refereeGroups: String[];
   /**
    * 比赛场地
    */
@@ -121,7 +120,7 @@ export interface GameEventProjectForm extends BaseEntity {
   projectName?: string;
 
   /**
-   * 项目类型(个人/团体)
+   * 项目类型
    */
   projectType?: string;
 
@@ -131,9 +130,9 @@ export interface GameEventProjectForm extends BaseEntity {
   groupType?: string;
 
   /**
-   * 裁判员ID
+   * 裁判
    */
-  refereeId?: string | number;
+  refereeGroups?: String[];
 
   /**
    * 比赛场地
@@ -233,7 +232,7 @@ export interface GameEventProjectQuery extends PageQuery {
   projectName?: string;
 
   /**
-   * 项目类型(个人/团体)
+   * 项目类型
    */
   projectType?: string;
 

+ 5 - 0
src/api/system/gameReferee/types.ts

@@ -106,6 +106,11 @@ export interface GameRefereeForm extends BaseEntity {
 
 export interface GameRefereeQuery extends PageQuery {
 
+  /**
+   * 裁判ID
+   */
+  refereeId?: string | number;
+
   /**
    * 赛事ID
    */

+ 37 - 8
src/views/system/gameEvent/RefereeForm.vue

@@ -29,7 +29,7 @@
 <script setup name="RefereeForm" lang="ts">
 import { reactive, ref } from 'vue';
 import { ElMessage } from 'element-plus';
-import { listGameEventProject } from '@/api/system/gameEventProject';
+import { listGameEventProject, updateGameEventProject,getGameEventProject } from '@/api/system/gameEventProject';
 import { addGameReferee } from '@/api/system/gameReferee';
 
 const dialog = reactive({
@@ -38,8 +38,8 @@ const dialog = reactive({
 });
 
 const form = reactive({
-  account: '',
-  password: '',
+  account: undefined,
+  password: undefined,
   projectIds: [] as string[]
 });
 
@@ -60,14 +60,15 @@ const loadProjects = async () => {
   const res = await listGameEventProject({
     eventId: eventId.value, // 使用传递进来的赛事ID
     pageNum: 1,
-    pageSize: 1000,
-    orderByColumn: '',
-    isAsc: ''
+    pageSize: 10,
+    orderByColumn: undefined,
+    isAsc: undefined,
   });
   allProjects.value = res.rows.map(item => ({
     key: String(item.projectId),
     label: `${item.projectName} - ${item.groupType}`
   }));
+  console.log(allProjects.value);
 };
 
 const openDialog = async (eventIdParam: string) => {
@@ -80,17 +81,45 @@ const cancel = () => {
   dialog.visible = false;
 };
 
-// 修改: 确保 form 在提交时包含 eventId
 const submitForm = () => {
   refereeFormRef.value.validate(async (valid: boolean) => {
     if (valid) {
       try {
         // 在 form 中添加 eventId
         const formData = { ...form, eventId: eventId.value };
-        await addGameReferee(formData);
+        const refereeResult = await addGameReferee(formData);
+        
+        // 获取新添加的裁判ID
+        const newRefereeId = refereeResult.data?.refereeId || null;
+        
+        // 更新所选项目的裁判组字段
+        if (newRefereeId && form.projectIds.length > 0) {
+          for (const projectId of form.projectIds) {
+            // 获取当前项目信息
+            const projectRes = await getGameEventProject(projectId);
+            
+            if (projectRes) {
+              const project = projectRes.data;
+              // 直接使用 refereeGroups 字段(字符串数组)
+              let currentRefereeGroups = project.refereeGroups || [];
+              // 检查是否已存在该裁判ID,避免重复添加
+              if (!currentRefereeGroups.includes(String(newRefereeId))) {
+                currentRefereeGroups.push(String(newRefereeId));
+              }
+              
+              // 更新项目表中的裁判组字段
+              await updateGameEventProject({
+                ...project,
+                refereeGroups: currentRefereeGroups
+              });
+            }
+          }
+        }
+        
         ElMessage.success('添加成功');
         dialog.visible = false;
       } catch (error) {
+        console.error('添加裁判失败:', error);
         ElMessage.error('添加失败');
       }
     }

+ 100 - 0
src/views/system/gameEventProject/RefereeGroupDialog.vue

@@ -0,0 +1,100 @@
+<template>
+  <el-dialog :title="`${projectName} - 裁判组成员`" v-model="dialog.visible" width="600px" append-to-body>
+    <div v-if="loading" class="text-center">
+      <el-icon class="is-loading"><Loading /></el-icon>
+      <span>加载中...</span>
+    </div>
+    
+    <div v-else>
+      <el-table :data="refereeList" border style="width: 100%">
+        <el-table-column label="裁判ID" align="center" prop="refereeId" width="80" />
+        <el-table-column label="裁判姓名" align="center" prop="name" />
+        <el-table-column label="账号" align="center" prop="account" />
+        <!-- <el-table-column label="负责项目" align="center" prop="projectNameList" /> -->
+      </el-table>
+      
+      <div v-if="refereeList.length === 0" class="text-center" style="padding: 20px; color: #999;">
+        暂无裁判组成员
+      </div>
+    </div>
+    
+    <template #footer>
+      <div class="dialog-footer">
+        <el-button @click="dialog.visible = false">关闭</el-button>
+      </div>
+    </template>
+  </el-dialog>
+</template>
+
+<script setup name="RefereeGroupDialog" lang="ts">
+import { reactive, ref } from 'vue';
+import { getGameReferee } from '@/api/system/gameReferee';
+import { GameRefereeVO } from '@/api/system/gameReferee/types';
+
+const dialog = reactive({
+  visible: false
+});
+
+const loading = ref(false);
+const projectName = ref('');
+const refereeList = ref<GameRefereeVO[]>([]);
+
+// 扩展GameRefereeVO类型,添加用于展示的projectNameList属性
+interface GameRefereeVOExt extends GameRefereeVO {
+  projectNameList?: string;
+}
+
+const openDialog = async (refereeGroups: string[], projectNameParam: string) => {
+  projectName.value = projectNameParam;
+  dialog.visible = true;
+  loading.value = true;
+  
+  try {
+    if (refereeGroups) {
+      // 解析裁判组ID列表
+      const refereeIds = refereeGroups.filter(id => id.trim());
+      
+      if (refereeIds.length > 0) {
+        // 获取裁判详细信息
+        const refereePromises = refereeIds.map(id => getGameReferee(id));
+        const refereeResults = await Promise.all(refereePromises);
+        
+        // 合并所有裁判信息
+        const allReferees: GameRefereeVOExt[] = [];
+        refereeResults.forEach(result => {
+          if (result.data) {
+            const referee = result.data as GameRefereeVOExt;
+            
+            // 处理项目名称列表显示
+            if (referee.projectList) {
+              // 这里可以根据需要格式化项目名称显示
+              referee.projectNameList = referee.projectList;
+            }
+            
+            allReferees.push(referee);
+          }
+        });
+        
+        refereeList.value = allReferees;
+      } else {
+        refereeList.value = [];
+      }
+    } else {
+      refereeList.value = [];
+    }
+  } catch (error) {
+    console.error('获取裁判组信息失败:', error);
+    refereeList.value = [];
+  } finally {
+    loading.value = false;
+  }
+};
+
+defineExpose({ openDialog });
+</script>
+
+<style scoped>
+.dialog-footer {
+  text-align: right;
+}
+</style> 

+ 36 - 13
src/views/system/gameEventProject/index.vue

@@ -70,7 +70,19 @@
             <span>{{ parseTime(scope.row.endTime, '{y}-{m}-{d}') }}</span>
           </template>
         </el-table-column>
-        <el-table-column label="裁判员ID" align="center" prop="refereeId" v-if="columns[8].visible" />
+        <el-table-column label="裁判组" align="center" prop="refereeGroup" v-if="columns[8].visible">
+          <template #default="scope">
+            <el-button 
+              v-if="scope.row.refereeGroups" 
+              type="primary" 
+              size="small" 
+              @click="handleViewRefereeGroup(scope.row.refereeGroups, scope.row.projectName)"
+            >
+              查看裁判组 ({{ scope.row.refereeGroups.length }}人)
+            </el-button>
+            <span v-else style="color: #999;">暂无裁判</span>
+          </template>
+        </el-table-column>
         <!-- <el-table-column label="参赛组数" align="center" prop="groupNum" />
         <el-table-column label="参赛人数" align="center" prop="participateNum" /> -->
         <el-table-column label="轮次" align="center" prop="roundType" v-if="columns[9].visible" />
@@ -116,10 +128,6 @@
             <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="裁判员ID" prop="refereeId">
-          <el-input v-model="form.refereeId" placeholder="请输入裁判员ID" />
-        </el-form-item> -->
         <el-form-item label="比赛场地" prop="location">
           <el-input v-model="form.location" placeholder="请输入比赛场地" />
         </el-form-item>
@@ -175,6 +183,9 @@
         </div>
       </template>
     </el-dialog>
+    
+    <!-- 裁判组查看对话框 -->
+    <RefereeGroupDialog ref="refereeGroupDialogRef" />
   </div>
 </template>
 
@@ -188,6 +199,7 @@ import {
 } from '@/api/system/gameEventProject';
 import { listGameEventGroup } from '@/api/system/gameEventGroup';
 import { GameEventProjectVO, GameEventProjectQuery, GameEventProjectForm } from '@/api/system/gameEventProject/types';
+import RefereeGroupDialog from './RefereeGroupDialog.vue';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { game_score_type, game_project_type } = toRefs<any>(proxy?.useDict('game_score_type', 'game_project_type'));
@@ -206,6 +218,13 @@ const total = ref(0);
 const queryFormRef = ref<ElFormInstance>();
 const gameEventProjectFormRef = ref<ElFormInstance>();
 
+// 定义 RefereeGroupDialog 组件的类型
+interface RefereeGroupDialogInstance {
+  openDialog: (refereeGroups: string[], projectName: string) => void;
+}
+
+const refereeGroupDialogRef = ref<(InstanceType<typeof RefereeGroupDialog> & RefereeGroupDialogInstance) | null>(null);
+
 const dialog = reactive<DialogOption>({
   visible: false,
   title: ''
@@ -221,7 +240,7 @@ const columns = ref<FieldOption[]>([
   { key: 5, label: '计算规则', visible: true },
   { key: 6, label: '开始时间', visible: true },
   { key: 7, label: '结束时间', visible: true },
-  { key: 8, label: '裁判员ID', visible: true },
+  { key: 8, label: '裁判', visible: true },
   { key: 9, label: '轮次', visible: true },
   { key: 10, label: '排序方式', visible: true },
   { key: 11, label: '积分分值', visible: true },
@@ -233,7 +252,7 @@ const initFormData: GameEventProjectForm = {
   projectName: undefined,
   projectType: undefined,
   groupType: undefined,
-  refereeId: undefined,
+  refereeGroups: undefined,
   location: undefined,
   startTime: undefined,
   endTime: undefined,
@@ -254,9 +273,8 @@ const data = reactive<PageData<GameEventProjectForm, GameEventProjectQuery>>({
   queryParams: {
     pageNum: 1,
     pageSize: 10,
-    eventId: undefined,
-    orderByColumn: '',
-    isAsc: ''
+    orderByColumn: undefined,
+    isAsc: undefined,
   },
   rules: {
     projectName: [{ required: true, message: '项目名称不能为空', trigger: 'blur' }],
@@ -281,9 +299,9 @@ const getList = async () => {
 const getGameEventGroupList = async () => {
   const res = await listGameEventGroup({
     pageNum: 1,
-    pageSize: 1000,
-    orderByColumn: '',
-    isAsc: ''
+    pageSize: 10,
+    orderByColumn: undefined,
+    isAsc: undefined,
   });
   gameEventGroupList.value = res.data;
 };
@@ -385,6 +403,11 @@ const handleExport = () => {
   );
 };
 
+/** 查看裁判组 */
+const handleViewRefereeGroup = (refereeGroups: string[], projectName: string) => {
+  refereeGroupDialogRef.value?.openDialog(refereeGroups, projectName);
+};
+
 onMounted(() => {
   getList();
   getGameEventGroupList();

+ 149 - 31
src/views/system/gameReferee/index.vue

@@ -115,7 +115,7 @@
 
 <script setup name="GameReferee" lang="ts">
 import { listGameReferee, getGameReferee, delGameReferee, addGameReferee, updateGameReferee } from '@/api/system/gameReferee';
-import { listGameEventProject } from '@/api/system/gameEventProject';
+import { getGameEventProject, listGameEventProject, updateGameEventProject } from '@/api/system/gameEventProject';
 import { GameRefereeVO, GameRefereeQuery, GameRefereeForm } from '@/api/system/gameReferee/types';
 import { toDataURL } from 'qrcode';
 
@@ -167,18 +167,18 @@ const dialog = reactive<DialogOption>({
   title: ''
 });
 
-// 定义表单数据结构,参考athlete.vue的实现方式
+// 定义表单数据结构
 const form = reactive({
   refereeId: undefined as string | number | undefined,
   eventId: undefined as string | number | undefined,
-  name: '',
-  groupName: '',
-  account: '',
-  password: '',
+  name: undefined,
+  groupName: undefined,
+  account: undefined,
+  password: undefined,
   projectList: [] as string[], // 存储所负责的项目
-  refereeCode: '',
-  createTime: '',
-  updateTime: ''
+  refereeCode: undefined,
+  createTime: undefined,
+  updateTime: undefined,
 });
 
 const queryParams = reactive<GameRefereeQuery>({
@@ -186,8 +186,8 @@ const queryParams = reactive<GameRefereeQuery>({
   pageSize: 10,
   name: undefined,
   params: {},
-  orderByColumn: '',
-  isAsc: ''
+  orderByColumn: undefined,
+  isAsc: undefined,
 });
 
 const rules = {
@@ -212,9 +212,9 @@ const getList = async () => {
       // 加载所有项目信息
       const projectRes = await listGameEventProject({
         pageNum: 1,
-        pageSize: 1000,
-        orderByColumn: '',
-        isAsc: ''
+        pageSize: 10,
+        orderByColumn: undefined,
+        isAsc: undefined,
       });
       
       // 获取项目ID数组
@@ -246,14 +246,14 @@ const reset = () => {
   Object.assign(form, {
     refereeId: undefined,
     eventId: undefined,
-    name: '',
-    groupName: '',
-    account: '',
-    password: '',
+    name: undefined,
+    groupName: undefined,
+    account: undefined,
+    password: undefined,
     projectList: [],
-    refereeCode: '',
-    createTime: '',
-    updateTime: ''
+    refereeCode: undefined,
+    createTime: undefined,
+    updateTime: undefined,
   });
   gameRefereeFormRef.value?.resetFields();
 }
@@ -288,9 +288,8 @@ const loadProjects = async () => {
   // 赛事项目穿梭框可选数据拼接
   allProjects.value = res.rows.map(item => ({
     key: String(item.projectId),
-    label: `${item.projectName}-${item.groupType}` // 根据规范,只显示项目名称,不拼接组别
+    label: `${item.projectName}-${item.groupType}` 
   }));
-
 };
 
 /** 新增按钮操作 */
@@ -311,7 +310,7 @@ const handleUpdate = async (row?: GameRefereeVO) => {
   // 如果是修改操作,先加载项目列表
   await loadProjects();
   
-  // 处理项目列表数据格式,参考athlete.vue的实现方式
+  // 处理项目列表数据格式
   if (res.data.projectList && typeof res.data.projectList === 'string') {
     form.projectList = res.data.projectList.split(',').filter(id => id);
   } else if (Array.isArray(res.data.projectList)) {
@@ -329,7 +328,7 @@ const submitForm = async () => {
   const valid = await gameRefereeFormRef.value?.validate();
   if (valid) {
     buttonLoading.value = true;
-    // 提交前处理项目列表数据格式,参考athlete.vue的实现方式
+    // 提交前处理项目列表数据格式
     const submitForm: any = { ...form };
     if (Array.isArray(form.projectList)) {
       submitForm.projectList = form.projectList.join(',');
@@ -337,13 +336,91 @@ const submitForm = async () => {
 
     try {
       if (form.refereeId) {
+        // 如果是更新操作,需要先获取原裁判信息,然后更新项目表中的裁判组
+        const originalReferee = await getGameReferee(form.refereeId);
+        const originalProjectList = originalReferee.data.projectList || '';
+        const newProjectList = submitForm.projectList || '';
+        
+        // 获取当前项目列表中的项目ID集合
+        const currentProjectIds = new Set<string>(newProjectList.split(',').filter(id => id.trim()));
+        
+        // 获取原项目列表中的项目ID集合
+        const originalProjectIds = new Set<string>(originalProjectList.split(',').filter(id => id.trim()));
+        
+        // 筛选出在原项目列表中但不在当前项目列表中的项目(即被删除的项目)
+        const removedProjectIds = Array.from(currentProjectIds).filter(id => !originalProjectIds.has(id));
+        
+        // 从被删除的项目中移除该裁判
+        for (const projectId of removedProjectIds) {
+          const projectRes = await getGameEventProject(projectId);
+          
+          if (projectRes) {
+            const project = projectRes.data;
+            let currentRefereeGroups = project.refereeGroups || [];
+            
+            // 从裁判组中移除该裁判ID
+            if (currentRefereeGroups) {
+              const refereeIds = currentRefereeGroups.filter(id => id.trim() !== String(form.refereeId));
+              // 更新项目表中的裁判组字段
+              await updateGameEventProject({
+                ...project,
+                refereeGroups: refereeIds
+              });
+            }
+          }
+        }
+        
+        // 向新项目中添加该裁判
+        const newProjectIds = Array.from<string>(currentProjectIds).filter(id => !originalProjectIds.has(id));
+        for (const projectId of newProjectIds) {
+          const projectRes = await getGameEventProject(projectId);
+          
+          if (projectRes) {
+            const project = projectRes.data;
+            let currentRefereeGroups = project.refereeGroups || [];
+            // 如果该项目的裁判组中没有该裁判,则添加
+            if(!project.refereeGroups.includes(String(form.refereeId))){
+              currentRefereeGroups.push(String(form.refereeId)) ;
+              await updateGameEventProject({
+                ...project,
+                refereeGroups: currentRefereeGroups
+              });
+            }
+          }
+        }
+        
         await updateGameReferee(submitForm as GameRefereeForm);
       } else {
-        await addGameReferee(submitForm as GameRefereeForm);
+        // 新增裁判
+        const refereeResult = await addGameReferee(submitForm as GameRefereeForm);
+        
+        // 获取新添加的裁判ID
+        const newRefereeId = refereeResult.data?.refereeId || refereeResult.data;
+        
+        // 更新所选项目的裁判组字段
+        if (newRefereeId && form.projectList.length > 0) {
+          for (const projectId of form.projectList) {
+            const projectRes = await getGameEventProject(projectId);
+            
+            if (projectRes) {
+              const project = projectRes.data;
+              let currentRefereeGroups = project.refereeGroups || [];
+              currentRefereeGroups.push(String(newRefereeId));
+              await updateGameEventProject({
+                ...project,
+                refereeGroups: currentRefereeGroups
+              });
+            }
+          }
+        }
       }
+      
       proxy?.$modal.msgSuccess("操作成功");
       dialog.visible = false;
       await getList();
+    } catch (error) {
+      console.error('操作失败:', error);
+      proxy?.$modal.msgError("操作失败");
     } finally {
       buttonLoading.value = false;
     }
@@ -352,11 +429,52 @@ const submitForm = async () => {
 
 /** 删除按钮操作 */
 const handleDelete = async (row?: GameRefereeVO) => {
-  const _refereeIds = row?.refereeId || ids.value;
-  await proxy?.$modal.confirm('是否确认删除裁判编号为"' + _refereeIds + '"的数据项?').finally(() => loading.value = false);
-  await delGameReferee(_refereeIds);
-  proxy?.$modal.msgSuccess("删除成功");
-  await getList();
+  const _refereeId = row?.refereeId || ids.value;
+  await proxy?.$modal.confirm('是否确认删除裁判编号为"' + _refereeId + '"的数据项?').finally(() => loading.value = false);
+  
+  try {
+    await delGameReferee(_refereeId);
+    
+    // 如果是单个删除,需要从项目表中移除该裁判
+    if (row) {
+      const refereeId = row.refereeId;
+      if (row.projectList) {
+        const projectIds = row.projectList.split(',').filter(id => id.trim());
+        
+        for (const projectId of projectIds) {
+          // 获取当前项目信息
+          const projectRes = await listGameEventProject({
+            projectId: projectId.trim(),
+            pageNum: 1,
+            pageSize: 10,
+            orderByColumn: undefined,
+            isAsc: undefined,
+          });
+          
+          if (projectRes.rows.length > 0) {
+            const project = projectRes.rows[0];
+            let currentRefereeGroups = project.refereeGroups || [];
+            
+            // 从裁判组中移除该裁判ID
+            if (currentRefereeGroups) {
+              const refereeIds = currentRefereeGroups.filter(id => id.trim() !== String(refereeId));
+              // 更新项目表中的裁判组字段
+              await updateGameEventProject({
+                ...project,
+                refereeGroups: refereeIds
+              });
+            }
+          }
+        }
+      }
+    }
+    
+    proxy?.$modal.msgSuccess("删除成功");
+    await getList();
+  } catch (error) {
+    console.error('删除裁判失败:', error);
+    proxy?.$modal.msgError("删除失败");
+  }
 }
 
 /** 生成裁判二维码 */