瀏覽代碼

feat(gameEventProject): 添加统计详情弹窗功能

- 新增StatsDetailDialog组件,支持查看运动员、代表队、分组详情
- 实现点击统计数字跳转详情弹窗功能
- 添加listTeamByProject API接口用于分页查询队伍信息
- 移除调试用console.log语句

BREAKING CHANGE: None
zhou 3 周之前
父節點
當前提交
8058f2181c

+ 2 - 2
src/App.vue

@@ -17,10 +17,10 @@ onMounted(() => {
       // 初始化主题样式,添加错误处理
       const settingsStore = useSettingsStore();
       const theme = settingsStore.theme;
-      console.log('初始化主题:', theme);
+      // console.log('初始化主题:', theme);
       handleThemeStyle(theme);
     } catch (error) {
-      console.warn('主题初始化失败,使用默认主题:', error);
+      // console.warn('主题初始化失败,使用默认主题:', error);
       // 使用默认主题色
       handleThemeStyle('#409EFF');
     }

+ 13 - 0
src/api/system/gameAthlete/index.ts

@@ -86,4 +86,17 @@ export function getAthleteCount(projectId: string | number, eventId?: string | n
     method: 'get',
     params: { eventId }
   });
+}
+
+/**
+ * 根据项目ID分页查询队伍详细信息
+ * @param projectId 项目ID
+ * @param query 分页参数
+ */
+export function listTeamByProject(projectId: string | number, query: any): AxiosPromise<any> {
+  return request({
+    url: '/system/gameAthlete/teamListByProject/' + projectId,
+    method: 'get',
+    params: query
+  });
 }

+ 2 - 2
src/config/api.ts

@@ -111,8 +111,8 @@ export const API_CONFIG_DEBUG = {
 
 // 在开发环境下打印环境信息
 if (isDev) {
-  console.log(' API配置信息:', API_CONFIG_DEBUG);
-  console.log(' 当前使用的API地址:', BASE_URL);
+  // console.log(' API配置信息:', API_CONFIG_DEBUG);
+  // console.log(' 当前使用的API地址:', BASE_URL);
 }
 
 // 手动切换环境的函数(仅用于调试)

+ 1 - 1
src/utils/sse.ts

@@ -20,7 +20,7 @@ export const initSSE = (url: any) => {
   });
 
   watch(error, () => {
-    console.log('SSE connection error:', error.value);
+    // console.log('SSE connection error:', error.value);
     error.value = null;
   });
 

+ 168 - 0
src/views/system/gameEventProject/StatsDetailDialog.vue

@@ -0,0 +1,168 @@
+<template>
+  <el-dialog :title="`${projectName} - ${dialogTitle}`" v-model="dialog.visible" width="900px" append-to-body>
+    <div v-loading="loading">
+      <el-table :data="list" border style="width: 100%" height="450px">
+        <el-table-column label="序号" align="center" type="index" />
+        <!-- 运动员列 -->
+        <template v-if="type === 'athlete'">
+          <el-table-column label="运动员编号" align="center" prop="athleteCode" />
+          <el-table-column label="姓名" align="center" prop="name" />
+          <el-table-column label="性别" align="center" prop="gender">
+            <template #default="scope">
+              <dict-tag :options="sys_user_sex" :value="scope.row.gender" />
+            </template>
+          </el-table-column>
+          <el-table-column label="联系电话" align="center" prop="phone" />
+        </template>
+
+        <!-- 代表队列 -->
+        <template v-if="type === 'team'">
+          <el-table-column label="队伍编号" align="center" prop="teamCode" />
+          <el-table-column label="队伍名称" align="center" prop="teamName" />
+          <el-table-column label="人数" align="center" prop="athleteNum" />
+          <el-table-column label="备注" align="center" prop="teamDescribe" />
+        </template>
+
+        <!-- 分组列 -->
+        <template v-if="type === 'group'">
+          <el-table-column label="分组名称" align="center" prop="groupName" />
+          <el-table-column label="性别" align="center" prop="memberGender" >
+            <template #default="scope">
+              <dict-tag :options="sys_group_sex" :value="scope.row.memberGender" />
+            </template>
+          </el-table-column>
+          <el-table-column label="符合条件人数" align="center" prop="eligibleAthleteCount" />
+          <el-table-column label="比赛时间" align="center" prop="beginTime" width="160" />
+        </template>
+      </el-table>
+
+      <pagination
+        v-show="total > 0"
+        :total="total"
+        v-model:page="queryParams.pageNum"
+        v-model:limit="queryParams.pageSize"
+        @pagination="getList"
+      />
+
+      <div v-if="list.length === 0 && !loading" 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="StatsDetailDialog" lang="ts">
+import { reactive, ref, toRefs, getCurrentInstance } from 'vue';
+import { listGameAthlete, listTeamByProject } from '@/api/system/gameAthlete';
+import { listGameTeam } from '@/api/system/gameTeam';
+import { listGameEventGroup } from '@/api/system/gameEventGroup';
+
+const { proxy } = getCurrentInstance() as any;
+const { sys_user_sex, sys_group_sex } = toRefs<any>(proxy?.useDict('sys_user_sex', 'sys_group_sex'));
+
+const dialog = reactive({
+  visible: false
+});
+
+const loading = ref(false);
+const projectName = ref('');
+const dialogTitle = ref('');
+const type = ref<'athlete' | 'team' | 'group'>('athlete');
+const list = ref<any[]>([]);
+const total = ref(0);
+const currentProjectId = ref<string | number>('');
+
+const queryParams = reactive({
+  pageNum: 1,
+  pageSize: 10,
+  projectId: undefined as string | number | undefined
+});
+
+/** 查询列表 */
+const getList = async () => {
+  loading.value = true;
+  try {
+    let res: any;
+    const query = { 
+      ...queryParams, 
+      projectId: currentProjectId.value,
+      orderByColumn: 'createTime', 
+      isAsc: 'desc' 
+    };
+
+    if (type.value === 'athlete') {
+      res = await listGameAthlete(query);
+    } else if (type.value === 'team') {
+      // 使用专门的新接口查询参与该项目的队伍
+      res = await listTeamByProject(currentProjectId.value, query);
+    } else if (type.value === 'group') {
+      res = await listGameEventGroup(query);
+    }
+
+    if (res && res.rows) {
+      list.value = res.rows;
+      total.value = res.total || res.rows.length;
+    } else if (res && res.data) {
+      // 兼容某些接口返回结构
+      if (Array.isArray(res.data)) {
+        list.value = res.data;
+        total.value = res.data.length;
+      } else {
+        list.value = res.data.rows || [];
+        total.value = res.data.total || list.value.length;
+      }
+    } else {
+      list.value = [];
+      total.value = 0;
+    }
+  } catch (error) {
+    console.error('获取详情失败:', error);
+    list.value = [];
+    total.value = 0;
+  } finally {
+    loading.value = false;
+  }
+};
+
+/** 打开弹窗 */
+const openDialog = (projectId: string | number, name: string, detailType: 'athlete' | 'team' | 'group') => {
+  projectName.value = name;
+  type.value = detailType;
+  currentProjectId.value = projectId;
+  
+  // 重置分页参数
+  queryParams.pageNum = 1;
+  queryParams.pageSize = 10;
+  
+  dialog.visible = true;
+
+  switch (detailType) {
+    case 'athlete':
+      dialogTitle.value = '参赛人员列表';
+      break;
+    case 'team':
+      dialogTitle.value = '参赛代表队列表';
+      break;
+    case 'group':
+      dialogTitle.value = '分组信息列表';
+      break;
+  }
+
+  getList();
+};
+
+defineExpose({ openDialog });
+</script>
+
+<style scoped>
+.dialog-footer {
+  text-align: right;
+  margin-top: 10px;
+}
+</style>

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

@@ -91,9 +91,27 @@
             <span v-else style="color: #999;">暂无裁判</span>
           </template>
         </el-table-column>
-        <el-table-column label="参赛人数" align="center" prop="athleteCount" v-if="columns[14].visible" />
-        <el-table-column label="代表队数" align="center" prop="teamCount" v-if="columns[15].visible" />
-        <el-table-column label="分组数" align="center" prop="groupCount" v-if="columns[16].visible" />
+        <el-table-column label="参赛人数" align="center" prop="athleteCount" v-if="columns[14].visible">
+          <template #default="scope">
+            <el-link type="primary" :underline="false" @click="handleViewStats(scope.row, 'athlete')">
+              {{ scope.row.athleteCount || 0 }}
+            </el-link>
+          </template>
+        </el-table-column>
+        <el-table-column label="代表队数" align="center" prop="teamCount" v-if="columns[15].visible">
+          <template #default="scope">
+            <el-link type="primary" :underline="false" @click="handleViewStats(scope.row, 'team')">
+              {{ scope.row.teamCount || 0 }}
+            </el-link>
+          </template>
+        </el-table-column>
+        <el-table-column label="分组数" align="center" prop="groupCount" v-if="columns[16].visible">
+          <template #default="scope">
+            <el-link type="primary" :underline="false" @click="handleViewStats(scope.row, 'group')">
+              {{ scope.row.groupCount || 0 }}
+            </el-link>
+          </template>
+        </el-table-column>
         <el-table-column label="录取名次" align="center" prop="roundType" v-if="columns[9].visible" />
         <el-table-column label="排序方式" align="center" prop="orderType" v-if="columns[10].visible">
           <template #default="scope">
@@ -221,6 +239,9 @@
 
     <!-- 项目库查看对话框 -->
     <ProjectLibraryDialog ref="projectLibraryDialog" @confirm="handleLibraryConfirm" />
+
+    <!-- 统计详情对话框 -->
+    <StatsDetailDialog ref="statsDetailDialogRef" />
   </div>
 </template>
 
@@ -238,6 +259,7 @@ import { listGameEventGroup } from '@/api/system/gameEventGroup';
 import { GameEventProjectVO, GameEventProjectQuery, GameEventProjectForm } from '@/api/system/gameEventProject/types';
 import RefereeGroupDialog from './RefereeGroupDialog.vue';
 import ProjectLibraryDialog from './ProjectLibraryDialog.vue';
+import StatsDetailDialog from './StatsDetailDialog.vue';
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { game_score_type, game_project_type, game_project_classification, game_round, game_stage } = toRefs<any>(proxy?.useDict('game_score_type', 'game_project_type', 'game_project_classification', 'game_round', 'game_stage'));
@@ -267,6 +289,7 @@ interface ProjectLibraryDialogInstance {
 
 const refereeGroupDialogRef = ref<(InstanceType<typeof RefereeGroupDialog> & RefereeGroupDialogInstance) | null>(null);
 const projectLibraryDialog = ref<(InstanceType<typeof ProjectLibraryDialog> & ProjectLibraryDialogInstance) | null>(null);
+const statsDetailDialogRef = ref<any>(null);
 
 const dialog = reactive<DialogOption>({
   visible: false,
@@ -463,6 +486,11 @@ const handleViewProjectLibrary = () => {
   projectLibraryDialog.value?.openDialog();
 };
 
+/** 查看统计详情 */
+const handleViewStats = (row: GameEventProjectVO, type: 'athlete' | 'team' | 'group') => {
+  statsDetailDialogRef.value?.openDialog(row.projectId, row.projectName, type);
+};
+
 /** 处理项目库选择确认 */
 const handleLibraryConfirm = async (projects: GameEventProjectVO[]) => {
   try {