Parcourir la source

feat(gameScore): 添加导出项目成绩详情功能

- 新增 exportProjectScore API 接口用于导出单个项目成绩详情
- 在游戏成绩编辑页面添加导出按钮和导出设置对话框
- 支持按前N名导出成绩详情,可选择导出前几名或全部成绩
- 优化性别列标签显示,将"姓名"修正为"性别"
- 实现文件下载和成功提示功能
zhou il y a 3 semaines
Parent
commit
6047009384

+ 15 - 0
src/api/system/gameScore/index.ts

@@ -187,3 +187,18 @@ export const exportBonusExcel = (data: {
     responseType: 'blob' // 确保以二进制流形式接收响应
   });
 };
+
+/**
+ * 导出单个项目成绩详情
+ * @param eventId 赛事ID
+ * @param projectId 项目ID
+ * @param topN 导出前几名
+ */
+export const exportProjectScore = (eventId: string | number, projectId: string | number, topN?: number) => {
+  return request({
+    url: '/system/gameScore/exportProjectScore',
+    method: 'post',
+    params: { eventId, projectId, topN },
+    responseType: 'blob'
+  });
+};

+ 61 - 2
src/views/system/gameScore/gameScoreEdit.vue

@@ -21,6 +21,9 @@
       <el-button type="success" @click="calculateRankings" :loading="rankingLoading">
         <el-icon><Trophy /></el-icon> 计算排名
       </el-button>
+      <el-button type="warning" @click="handleExport">
+        <el-icon><Download /></el-icon> 导出
+      </el-button>
       <el-input 
         v-model="searchValue" 
         :placeholder="projectClassification === '0' ? '输入运动员姓名搜索' : '输入队伍名称搜索'" 
@@ -56,7 +59,7 @@
         <template v-if="projectClassification === '0'">
           <el-table-column label="号码" align="center" prop="athleteCode" />
           <el-table-column label="姓名" align="center" prop="name" />
-          <el-table-column label="姓名" align="center" prop="gender" >
+          <el-table-column label="性别" align="center" prop="gender" >
             <template #default="scope">
               <dict-tag :options="sys_user_sex" :value="scope.row.gender" />
             </template>
@@ -129,13 +132,29 @@
     </el-dialog>
 
     <pagination v-show="total > 0" :total="total" v-model:page="queryParams.pageNum" v-model:limit="queryParams.pageSize" @pagination="handlePagination({page: queryParams.pageNum, limit: queryParams.pageSize})" />
+
+    <!-- 导出设置对话框 -->
+    <el-dialog title="导出成绩详情" v-model="exportDialog.visible" width="400px" append-to-body>
+      <el-form label-width="120px">
+        <el-form-item label="导出前几名:">
+          <el-input-number v-model="exportDialog.topN" :min="0" :precision="0" placeholder="不输入导出所有" style="width: 100%" />
+          <div class="help-block" style="color: #999; font-size: 12px; margin-top: 5px;">提示:输入 0 或不输入表示导出所有成绩</div>
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="doExport" :loading="exportLoading">确 定</el-button>
+          <el-button @click="exportDialog.visible = false">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
   </div>
 </template>
 
 <script setup name="GameScoreEdit" lang="ts">
 import { onMounted, onUnmounted, ref, reactive, getCurrentInstance, toRefs } from 'vue';
 import { useRoute } from 'vue-router';
-import { getProjectScoreData, updateScoreAndRecalculate } from '@/api/system/gameScore/index';
+import { getProjectScoreData, updateScoreAndRecalculate, exportProjectScore } from '@/api/system/gameScore/index';
 import { GameScoreForm } from '@/api/system/gameScore/types';
 import Pagination from '@/components/Pagination/index.vue';
 import type { ComponentInternalInstance } from 'vue';
@@ -150,6 +169,12 @@ const dataList = ref<any[]>([]);
 const loading = ref(true);
 const total = ref(0);
 const pickAthletes = ref('');
+const exportLoading = ref(false);
+
+const exportDialog = reactive({
+  visible: false,
+  topN: undefined as number | undefined
+});
 
 // 定义搜索框状态变量
 const searchValue = ref('');
@@ -440,6 +465,40 @@ const submitForm = async () => {
   });
 };
 
+/** 导出按钮操作 */
+const handleExport = () => {
+  exportDialog.topN = undefined;
+  exportDialog.visible = true;
+};
+
+/** 执行导出 */
+const doExport = async () => {
+  try {
+    exportLoading.value = true;
+    const response = await exportProjectScore(eventId, projectId, exportDialog.topN || 0);
+    
+    // 生成文件名
+    const classificationStr = projectClassification === '0' ? '个人' : '团体';
+    const fileName = `${classificationStr}_${projectName}_成绩详情.xlsx`;
+    
+    // 下载文件
+    const blob = new Blob([response as any]);
+    const link = document.createElement('a');
+    link.href = window.URL.createObjectURL(blob);
+    link.download = fileName;
+    link.click();
+    window.URL.revokeObjectURL(link.href);
+    
+    proxy?.$modal.msgSuccess("导出成功");
+    exportDialog.visible = false;
+  } catch (error) {
+    // console.error("导出失败:", error);
+    proxy?.$modal.msgError("导出失败,请稍后再试");
+  } finally {
+    exportLoading.value = false;
+  }
+};
+
 // 加载数据方法,支持搜索
 const loadData = async (autoCalculateRanking = false) => {
   loading.value = true;