Browse Source

refactor(system): 重构裁判相关功能

- 修改裁判项目列表数据类型,从字符串改为数字
- 优化项目列表显示和处理逻辑
- 添加生成裁判二维码功能
- 调整表格列显示内容
- 移除冗余代码,优化代码结构
zhou 1 month ago
parent
commit
6ad93784b6

+ 1 - 1
.env.production

@@ -14,7 +14,7 @@ VITE_APP_MONITOR_ADMIN = '/admin/applications'
 VITE_APP_SNAILJOB_ADMIN = '/snail-job'
 
 # 生产环境
-VITE_APP_BASE_API = '/prod-api'
+VITE_APP_BASE_API = 'http://meet2.sportsrobo.club:8080'
 
 # 是否在打包时开启压缩,支持 gzip 和 brotli
 VITE_BUILD_COMPRESS = gzip

+ 3 - 3
package.json

@@ -22,7 +22,7 @@
   "dependencies": {
     "@element-plus/icons-vue": "2.3.1",
     "@highlightjs/vue-plugin": "2.1.0",
-    "@types/qrcode": "^1.5.5",
+    
     "@vueup/vue-quill": "1.2.0",
     "@vueuse/core": "13.1.0",
     "animate.css": "4.1.1",
@@ -38,14 +38,14 @@
     "jsencrypt": "3.3.2",
     "nprogress": "0.2.0",
     "pinia": "3.0.2",
-    "qrcode": "^1.5.4",
+    
     "screenfull": "6.0.2",
     "vue": "3.5.13",
     "vue-cropper": "1.1.1",
     "vue-cropperjs": "^5.0.0",
     "vue-i18n": "11.1.3",
     "vue-json-pretty": "2.4.0",
-    "vue-qr": "^4.0.9",
+    
     "vue-router": "4.5.0",
     "vue-types": "6.0.0",
     "vxe-table": "4.13.7"

+ 3 - 3
src/api/system/gameAthlete/types.ts

@@ -73,7 +73,7 @@ export interface GameAthleteVO {
    * 参与项目列表
    */
   projectValue: string;
-  projectList: String[];
+  projectList: number[];
 
   /**
    * 状态(0正常 1停用)
@@ -166,12 +166,12 @@ export interface GameAthleteForm extends BaseEntity {
    * 参与项目列表
    */
   projectValue?: string;
-  projectList: String[];
+  projectList: number[];
 
   /**
    * 选中的项目列表(用于穿梭框)
    */
-  selectedProjects?: string[];
+  selectedProjects?: number[];
 
   /**
    * 状态(0正常 1停用)

+ 1 - 1
src/api/system/gameEventGroup/types.ts

@@ -111,7 +111,7 @@ export interface GameEventGroupForm extends BaseEntity {
   /**
    * 选中的项目列表(用于穿梭框)
    */
-  selectedProjects?: string[];
+  selectedProjects?: number[];
 
   /**
    * 成员性别(0不限1男2女)

+ 2 - 2
src/api/system/gameEventProject/types.ts

@@ -26,7 +26,7 @@ export interface GameEventProjectVO {
   /**
    * 裁判组员
    */
-  refereeGroups: String[];
+  refereeGroups: number[];
   /**
    * 比赛场地
    */
@@ -132,7 +132,7 @@ export interface GameEventProjectForm extends BaseEntity {
   /**
    * 裁判组员
    */
-  refereeGroups?: String[];
+  refereeGroups?: number[];
 
   /**
    * 比赛场地

+ 13 - 1
src/api/system/gameReferee/index.ts

@@ -1,4 +1,4 @@
-import request from '@/utils/request';
+import request from '@/utils/request';
 import { AxiosPromise } from 'axios';
 import { GameRefereeVO, GameRefereeForm, GameRefereeQuery } from '@/api/system/gameReferee/types';
 
@@ -72,3 +72,15 @@ export const getRefereeCount = () => {
     method: 'get'
   });
 };
+
+/**
+ * 生成裁判二维码
+ * @param refereeId 裁判ID
+ * @returns {*}
+ */
+export const generateRefereeQRCode = (refereeId: string | number): AxiosPromise<string> => {
+  return request({
+    url: '/system/gameReferee/qrcode/' + refereeId,
+    method: 'get'
+  });
+};

+ 2 - 2
src/api/system/gameReferee/types.ts

@@ -33,7 +33,7 @@ export interface GameRefereeVO {
    * 负责的项目
    */
   projectList: string;
-  projectList2: string[];
+  projectList2: number[];
 
   /**
    * 裁判码
@@ -87,7 +87,7 @@ export interface GameRefereeForm extends BaseEntity {
    * 负责的项目
    */
   projectList?: string;
-  projectList2?: string[];
+  projectList2?: number[];
 
   /**
    * 裁判码

+ 7 - 7
src/views/system/gameAthlete/index.vue

@@ -56,7 +56,7 @@
 
       <el-table v-loading="loading" border :data="gameAthleteList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="主键" align="center" prop="athleteId" v-if="columns[0].visible" />
+        <el-table-column label="运动员id" align="center" prop="athleteId" v-if="columns[0].visible" />
         <el-table-column label="赛事名称" align="center" prop="eventName" width="120px" v-if="columns[1].visible" />
         <el-table-column label="号码" align="center" prop="athleteCode" width="100px" v-if="columns[2].visible" />
         <el-table-column label="姓名" align="center" prop="name" v-if="columns[3].visible" />
@@ -209,7 +209,7 @@ const total = ref(0);
 
 // 列显隐数据
 const columns = ref<FieldOption[]>([
-  { key: 0, label: '主键', visible: false },
+  { key: 0, label: '运动员id', visible: false },
   { key: 1, label: '赛事名称', visible: false },
   { key: 2, label: '号码', visible: true },
   { key: 3, label: '姓名', visible: true },
@@ -297,7 +297,6 @@ const data = reactive<PageData<GameAthleteForm, GameAthleteQuery>>({
     teamId: [{ required: true, message: '队伍ID不能为空', trigger: 'blur' }],
     athleteCode: [{ required: true, message: '运动员编号不能为空', trigger: 'blur' }],
     gender: [{ required: true, message: '性别不能为空', trigger: 'blur' }],
-    age: [{ required: true, message: '年龄不能为空', trigger: 'blur' }]
   }
 });
 
@@ -325,7 +324,8 @@ const { queryParams, form, rules } = toRefs(data);
 // };
 
 /** 获取队伍名称 */
-const getTeamNameById = (teamId: string | number) => {
+const getTeamNameById = (teamId: string | number | null | undefined) => {
+  if (!teamId) return '';
   const team = gameTeamList.value.find((team) => team.teamId === teamId);
   return team ? team.teamName : '';
 };
@@ -346,7 +346,7 @@ const getProjectList = async (eventId?: string) => {
 };
 
 // 格式化项目列表显示
-const formatProjectList = (projectList: string[]) => {
+const formatProjectList = (projectList: number[]) => {
   if (!projectList) return '';
   // 将逗号分隔的ID列表转换为项目名称列表
   // const projectIds = projectValue.split(',');
@@ -354,7 +354,7 @@ const formatProjectList = (projectList: string[]) => {
   //   const project = gameEventProjectList.value.find((p) => p.key === id);
   //   return project ? project.label : id;
   // });
-  const projectNames = gameEventProjectList.value.filter((p) => projectList.includes(p.key)).map((p) => p.label);
+  const projectNames = gameEventProjectList.value.filter((p) => projectList.includes(Number(p.key))).map((p) => p.label);
   return projectNames.join(',');
 };
 
@@ -433,7 +433,7 @@ const handleUpdate = async (row?: GameAthleteVO) => {
 
   // 处理项目列表,将逗号分隔的字符串转换为数组
   if (res.data.projectValue) {
-    form.value.selectedProjects = res.data.projectValue.split(',');
+    form.value.selectedProjects = res.data.projectValue.split(',').map(Number);
   } else {
     form.value.selectedProjects = [];
   }

+ 2 - 2
src/views/system/gameEvent/RefereeForm.vue

@@ -126,8 +126,8 @@ const submitForm = () => {
               // 直接使用 refereeGroups 字段(字符串数组)
               let currentRefereeGroups = project.refereeGroups || [];
               // 检查是否已存在该裁判ID,避免重复添加
-              if (!currentRefereeGroups.includes(String(newRefereeId))) {
-                currentRefereeGroups.push(String(newRefereeId));
+              if (!currentRefereeGroups.includes(newRefereeId)) {
+                currentRefereeGroups.push(newRefereeId);
               }
               
               // 更新项目表中的裁判组字段

+ 1 - 4
src/views/system/gameEvent/athlete.vue

@@ -93,7 +93,7 @@ const athleteForm = reactive({
   unit: '',
   age: 0,
   gender: '',
-  projectValue: [] as string[]  // 确保初始化为数组
+  projectValue: [] as number[]  // 确保初始化为数组
 });
 
 const athleteRules = {
@@ -103,9 +103,6 @@ const athleteRules = {
   athleteCode: [
     { required: true, message: '请输入号码', trigger: 'blur' }
   ],
-  age: [
-    { required: true, message: '请输入年龄', trigger: 'blur' }
-  ],
   gender: [
     { required: true, message: '请选择性别', trigger: 'change' }
   ]

+ 2 - 2
src/views/system/gameEventConfig/index.vue

@@ -50,7 +50,7 @@
 
       <el-table v-loading="loading" border :data="gameEventConfigList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="主键" align="center" prop="configId" v-if="columns[0].visible" />
+        <el-table-column label="配置id" align="center" prop="configId" v-if="columns[0].visible" />
         <!-- <el-table-column label="赛事ID" align="center" prop="eventId" /> -->
         <el-table-column label="配置类型" align="center" prop="configType" v-if="columns[1].visible" />
         <el-table-column label="配置描述" align="center" prop="configDesc" v-if="columns[2].visible" />
@@ -146,7 +146,7 @@ const total = ref(0);
 
 // 列显隐数据
 const columns = ref<FieldOption[]>([
-  { key: 0, label: '主键', visible: true },
+  { key: 0, label: '配置id', visible: true },
   { key: 1, label: '配置类型', visible: true },
   { key: 2, label: '配置描述', visible: true },
   { key: 3, label: '配置键', visible: true },

+ 2 - 2
src/views/system/gameEventConfigType/index.vue

@@ -51,7 +51,7 @@
 
       <el-table v-loading="loading" border :data="gameEventConfigTypeList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="主键" align="center" prop="typeId" v-if="columns[0].visible" />
+        <el-table-column label="类型id" align="center" prop="typeId" v-if="columns[0].visible" />
         <el-table-column label="类型编码" align="center" prop="typeCode" v-if="columns[1].visible" />
         <el-table-column label="类型名称" align="center" prop="typeName" v-if="columns[2].visible" />
         <el-table-column label="类型描述" align="center" prop="typeDesc" v-if="columns[3].visible" />
@@ -144,7 +144,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 },

+ 2 - 2
src/views/system/gameEventProject/RefereeGroupDialog.vue

@@ -44,7 +44,7 @@ interface GameRefereeVOExt extends GameRefereeVO {
   projectNameList?: string;
 }
 
-const openDialog = async (refereeGroups: string[], projectNameParam: string) => {
+const openDialog = async (refereeGroups: number[], projectNameParam: string) => {
   projectName.value = projectNameParam;
   dialog.visible = true;
   loading.value = true;
@@ -52,7 +52,7 @@ const openDialog = async (refereeGroups: string[], projectNameParam: string) =>
   try {
     if (refereeGroups) {
       // 解析裁判组ID列表
-      const refereeIds = refereeGroups.filter(id => id.trim());
+      const refereeIds = refereeGroups.filter(id => id);
       
       if (refereeIds.length > 0) {
         // 获取裁判详细信息

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

@@ -46,7 +46,7 @@
 
       <el-table v-loading="loading" border :data="gameEventProjectList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <el-table-column label="主键" align="center" prop="projectId" v-if="columns[0].visible" />
+        <el-table-column label="项目id" align="center" prop="projectId" v-if="columns[0].visible" />
         <el-table-column label="项目名称" align="center" prop="projectName" v-if="columns[1].visible" />
         <el-table-column label="项目类型" align="center" prop="projectType" v-if="columns[2].visible">
           <template #default="scope">
@@ -240,7 +240,7 @@ const dialog = reactive<DialogOption>({
 
 // 列显隐数据
 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 },

+ 29 - 110
src/views/system/gameReferee/index.vue

@@ -80,7 +80,7 @@
         <el-form-item label="赛事项目" prop="projectList2">
           <!-- 赛事项目穿梭框 -->
           <el-transfer
-            v-model="form.projectList2"
+            v-model="projectList2Str"
             :data="allProjects"
             :titles="['可选项目', '已选项目']"
             :button-texts="['移除', '添加']"
@@ -114,10 +114,9 @@
 </template>
 
 <script setup name="GameReferee" lang="ts">
-import { listGameReferee, getGameReferee, delGameReferee, addGameReferee, updateGameReferee } from '@/api/system/gameReferee';
+import { listGameReferee, getGameReferee, delGameReferee, addGameReferee, updateGameReferee, generateRefereeQRCode } from '@/api/system/gameReferee';
 import { getGameEventProject, listGameEventProject, updateGameEventProject } from '@/api/system/gameEventProject';
 import { GameRefereeVO, GameRefereeQuery, GameRefereeForm } from '@/api/system/gameReferee/types';
-import { toDataURL } from 'qrcode';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 
@@ -133,7 +132,7 @@ const allProjects = ref<{key: string, label: string }[]>([]); // 添加项目数
 
 // 列显隐数据
 const columns = ref<FieldOption[]>([
-  { key: 0, label: '裁判ID', visible: true },
+  { key: 0, label: '裁判ID', visible: false },
   { key: 1, label: '裁判姓名', visible: true },
   { key: 2, label: '账号', visible: true },
   { key: 3, label: '密码', visible: true },
@@ -176,7 +175,7 @@ const form = reactive({
   account: undefined,
   password: undefined,
   // projectList: [] as string[], // 存储所负责的项目
-  projectList2: [] as string[], // 存储所负责的项目
+  projectList2: [] as number[], // 存储所负责的项目
   refereeCode: undefined,
   createTime: undefined,
   updateTime: undefined,
@@ -223,7 +222,7 @@ const getList = async () => {
       
       // 从所有项目中筛选出在projectIds中存在的项目,并提取它们的label值(项目名称)
       const projectNames = projectRes.rows
-        .filter(project => projectIds.includes(String(project.projectId)))
+        .filter(project => projectIds.map(id => Number(id)).includes(Number(project.projectId)))
         .map(project => project.projectName);
       
       // 添加projectNameList属性到裁判对象中用于展示
@@ -260,6 +259,14 @@ const reset = () => {
   gameRefereeFormRef.value?.resetFields();
 }
 
+// 添加一个计算属性用于处理projectList2的类型转换
+const projectList2Str = computed({
+  get: () => form.projectList2.map(id => String(id)),
+  set: (value) => {
+    form.projectList2 = value.map(id => Number(id));
+  }
+});
+
 /** 搜索按钮操作 */
 const handleQuery = () => {
   queryParams.pageNum = 1;
@@ -308,20 +315,18 @@ const handleUpdate = async (row?: GameRefereeVO) => {
   const _refereeId = row?.refereeId || ids.value[0]
   const res = await getGameReferee(_refereeId);
   Object.assign(form, res.data);
-  
-  // 如果是修改操作,先加载项目列表
+
+  // 等待项目列表加载完成
   await loadProjects();
-  
+
   // 处理项目列表数据格式
-  // if (res.data.projectList && typeof res.data.projectList === 'string') {
-  //   form.projectList = res.data.projectList.split(',').filter(id => id);
-  // } else 
   if (Array.isArray(res.data.projectList2)) {
-    form.projectList2 = res.data.projectList2;
+    // 将数字数组转换为字符串数组,以匹配 allProjects 的 key 类型
+    form.projectList2 = res.data.projectList2.map(id => id);
   } else {
     form.projectList2 = [];
   }
-  
+
   dialog.visible = true;
   dialog.title = "修改裁判";
 }
@@ -331,103 +336,23 @@ const submitForm = async () => {
   const valid = await gameRefereeFormRef.value?.validate();
   if (valid) {
     buttonLoading.value = true;
-    // 提交前处理项目列表数据格式
     const submitForm: any = { ...form };
-    // if (Array.isArray(form.projectList)) {
-    //   submitForm.projectList = form.projectList.join(',');
-    // }
     if (form.projectList2) {
       submitForm.projectList2 = form.projectList2;
     }
 
     try {
       if (form.refereeId) {
-        // 如果是更新操作,需要先获取原裁判信息,然后更新项目表中的裁判组
-        const originalReferee = await getGameReferee(form.refereeId);
-        const originalProjectList = originalReferee.data.projectList2 || [];
-        const newProjectList = submitForm.projectList2 || [];
-        
-        // 获取当前项目列表中的项目ID集合
-        // const currentProjectIds = new Set<string>(newProjectList.filter(id => id.trim()));
-        
-        // 获取原项目列表中的项目ID集合
-        // const originalProjectIds = new Set<string>(originalProjectList.filter(id => id.trim()));
-        
-        // 筛选出在原项目列表中但不在当前项目列表中的项目(即被删除的项目)
-        // const removedProjectIds = Array.from(currentProjectIds).filter(id => !originalProjectIds.has(id));
-        const removedProjectIds = newProjectList.filter(id => !originalProjectList.includes(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(
-        const newProjectIds = newProjectList.filter(id => !originalProjectList.includes(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 {
-        // 新增裁判
-        const refereeResult = await addGameReferee(submitForm as GameRefereeForm);
-        
-        // 获取新添加的裁判ID
-        const newRefereeId = refereeResult.data?.refereeId || refereeResult.data;
-        
-        // 更新所选项目的裁判组字段
-        if (newRefereeId && form.projectList2.length > 0) {
-          for (const projectId of form.projectList2) {
-            const projectRes = await getGameEventProject(projectId);
-            
-            if (projectRes) {
-              const project = projectRes.data;
-              let currentRefereeGroups = project.refereeGroups || [];
-              currentRefereeGroups.push(String(newRefereeId));
-              await updateGameEventProject({
-                ...project,
-                refereeGroups: currentRefereeGroups
-              });
-            }
-          }
-        }
+        await addGameReferee(submitForm as GameRefereeForm);
       }
       
       proxy?.$modal.msgSuccess("操作成功");
       dialog.visible = false;
       await getList();
     } catch (error) {
-      console.error('操作失败:', error);
+      console.error("操作失败:", error);
       proxy?.$modal.msgError("操作失败");
     } finally {
       buttonLoading.value = false;
@@ -447,11 +372,11 @@ const handleDelete = async (row?: GameRefereeVO) => {
     if (row) {
       const refereeId = row.refereeId;
       if (row.projectList2) {
-        const projectIds = row.projectList2.filter(id => id.trim());
+        const projectIds = row.projectList2.filter(id => id);
         
         for (const projectId of projectIds) {
           // 获取当前项目信息
-          const getProject = await getGameEventProject(projectId.trim());
+          const getProject = await getGameEventProject(projectId);
           const project = getProject.data;
           if (project) {
             
@@ -459,7 +384,7 @@ const handleDelete = async (row?: GameRefereeVO) => {
             
             // 从裁判组中移除该裁判ID
             if (currentRefereeGroups) {
-              const refereeIds = currentRefereeGroups.filter(id => id.trim() !== String(refereeId));
+              const refereeIds = currentRefereeGroups.filter(id => id !== refereeId);
               // 更新项目表中的裁判组字段
               await updateGameEventProject({
                 ...project,
@@ -482,18 +407,12 @@ const handleDelete = async (row?: GameRefereeVO) => {
 /** 生成裁判二维码 */
 const handleGenerateQRCode = async (row: GameRefereeVO) => {
   currentReferee.value = row;
-  // 生成二维码数据,可以包含裁判的基本信息
-  const qrData = {
-    eventId: row.eventId,
-    refereeId: row.refereeId,
-    name: row.name,
-    account: row.account,
-    password: row.password,
-    projectList: row.projectList2,
-  };
   
   try {
-    qrCodeData.value = await toDataURL(JSON.stringify(qrData), { width: 200 });
+    // 生成二维码数据
+    const res = await generateRefereeQRCode(row.refereeId);
+    qrCodeData.value = res.data;
+    console.log('二维码数据:', res);
     qrCodeDialog.visible = true;
   } catch (error) {
     proxy?.$modal.msgError("生成二维码失败");
@@ -522,4 +441,4 @@ onMounted(() => {
   getList();
 });
 
-</script>
+</script>

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

@@ -47,8 +47,8 @@
 
       <el-table v-loading="loading" border :data="gameTeamList" @selection-change="handleSelectionChange">
         <el-table-column type="selection" width="55" align="center" />
-        <!--        <el-table-column label="主键" align="center" prop="teamId" v-if="columns[0].visible" />-->
-        <!--        <el-table-column label="队伍编号" align="center" prop="teamCode" v-if="columns[1].visible" />-->
+        <el-table-column label="队伍id" align="center" prop="teamId" v-if="columns[0].visible" />
+        <el-table-column label="队伍编号" align="center" prop="teamCode" 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="teamName" v-if="columns[3].visible" />
         <el-table-column label="团队描述" align="center" prop="teamDescribe" v-if="columns[4].visible">
@@ -168,8 +168,8 @@ const eventOptions = ref<Array<{ label: string; value: string | number }>>([]);
 
 // 列显隐数据
 const columns = ref<FieldOption[]>([
-  { key: 0, label: '主键', visible: false },
-  { key: 1, label: '队伍编号', visible: true },
+  { key: 0, label: '队伍id', visible: false },
+  { key: 1, label: '队伍编号', visible: false },
   { key: 2, label: '赛事名称', visible: false },
   { key: 3, label: '队伍名称', visible: true },
   { key: 4, label: '团队描述', visible: true },