|
@@ -4,23 +4,9 @@
|
|
|
<div v-show="showSearch" class="mb-[10px]">
|
|
|
<el-card shadow="hover">
|
|
|
<el-form ref="queryFormRef" :model="queryParams" :inline="true">
|
|
|
- <!-- <el-form-item label="赛事" prop="eventId">
|
|
|
- <el-select v-model="queryParams.eventId" placeholder="请选择赛事" clearable filterable @change="handleEventChange">
|
|
|
- <el-option
|
|
|
- v-for="event in eventList"
|
|
|
- :key="event.eventId"
|
|
|
- :label="event.eventName"
|
|
|
- :value="event.eventId">
|
|
|
- </el-option>
|
|
|
- </el-select>
|
|
|
- </el-form-item> -->
|
|
|
<el-form-item label="项目" prop="projectId">
|
|
|
<el-select v-model="queryParams.projectId" placeholder="请选择项目" clearable filterable>
|
|
|
- <el-option
|
|
|
- v-for="project in projectList"
|
|
|
- :key="project.projectId"
|
|
|
- :label="project.projectName"
|
|
|
- :value="project.projectId">
|
|
|
+ <el-option v-for="project in projectList" :key="project.projectId" :label="project.projectName" :value="project.projectId">
|
|
|
</el-option>
|
|
|
</el-select>
|
|
|
</el-form-item>
|
|
@@ -43,14 +29,11 @@
|
|
|
<el-button type="primary" @click="refreshData">刷新</el-button>
|
|
|
</el-col>
|
|
|
<el-col :span="1.5">
|
|
|
- <el-button type="primary" @click="printScores">打印成绩(仅有名次)</el-button>
|
|
|
+ <el-button type="primary" @click="printScores">打印成绩(前3名)</el-button>
|
|
|
</el-col>
|
|
|
<el-col :span="1.5">
|
|
|
<el-button type="primary" @click="exportScoresNames">导出成绩(全部)</el-button>
|
|
|
</el-col>
|
|
|
- <el-col :span="1.5">
|
|
|
- <el-button type="primary" @click="exportNumberMapping">导出号码对照表</el-button>
|
|
|
- </el-col>
|
|
|
<right-toolbar v-model:showSearch="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
|
|
|
</el-row>
|
|
|
</template>
|
|
@@ -69,12 +52,12 @@
|
|
|
<el-table v-loading="loading" border :data="projectList" @selection-change="handleSelectionChange">
|
|
|
<el-table-column type="selection" width="55" align="center" />
|
|
|
<el-table-column label="ID" align="center" prop="projectId" v-if="columns[0].visible" />
|
|
|
- <el-table-column label="项目类型" align="center" prop="projectType" v-if="columns[2].visible" >
|
|
|
+ <el-table-column label="项目类型" align="center" prop="projectType" v-if="columns[2].visible">
|
|
|
<template #default="scope">
|
|
|
<dict-tag :options="game_project_type" :value="scope.row.projectType" />
|
|
|
</template>
|
|
|
</el-table-column>
|
|
|
- <el-table-column label="归类" align="center" prop="classification" v-if="columns[3].visible" >
|
|
|
+ <el-table-column label="归类" align="center" prop="classification" v-if="columns[3].visible">
|
|
|
<template #default="scope">
|
|
|
<el-tag :type="scope.row.classification === '0' ? 'success' : 'warning'">
|
|
|
{{ scope.row.classification === '0' ? '个人项目' : '团体项目' }}
|
|
@@ -83,7 +66,7 @@
|
|
|
</el-table-column>
|
|
|
<el-table-column label="项目" align="center" prop="projectName" v-if="columns[1].visible" />
|
|
|
<!-- <el-table-column label="分组" align="center" prop="groupType" v-if="columns[2].visible" /> -->
|
|
|
-
|
|
|
+
|
|
|
<el-table-column label="状态" align="center" prop="status" v-if="columns[4].visible">
|
|
|
<template #default="scope">
|
|
|
<el-select v-model="scope.row.status" placeholder="请选择状态">
|
|
@@ -109,19 +92,34 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup name="GameScore" lang="ts">
|
|
|
-import { listGameScore, getGameScore, delGameScore, addGameScore, updateGameScore } from '@/api/system/gameScore';
|
|
|
-import { getDefaultEvent } from '@/api/system/gameEvent'
|
|
|
+import {
|
|
|
+ listGameScore,
|
|
|
+ getGameScore,
|
|
|
+ delGameScore,
|
|
|
+ addGameScore,
|
|
|
+ updateGameScore,
|
|
|
+ getProjectScoreData,
|
|
|
+ exportScoresSummary
|
|
|
+} from '@/api/system/gameScore';
|
|
|
+import { getDefaultEvent } from '@/api/system/gameEvent';
|
|
|
import { listGameEventProject } from '@/api/system/gameEventProject';
|
|
|
+import { getGameTeam } from '@/api/system/gameTeam';
|
|
|
+import { getGameAthlete } from '@/api/system/gameAthlete';
|
|
|
import { GameScoreVO, GameScoreQuery, GameScoreForm } from '@/api/system/gameScore/types';
|
|
|
import { GameEventVO, GameEventQuery } from '@/api/system/gameEvent/types';
|
|
|
import { GameEventProjectVO, GameEventProjectQuery } from '@/api/system/gameEventProject/types';
|
|
|
+import { GameTeamVO } from '@/api/system/gameTeam/types';
|
|
|
+import { GameAthleteVO } from '@/api/system/gameAthlete/types';
|
|
|
+import { ElLoading, ElMessage } from 'element-plus';
|
|
|
+import { useGameEventStore } from '@/store/modules/gameEvent';
|
|
|
|
|
|
const { proxy } = getCurrentInstance() as ComponentInternalInstance;
|
|
|
const { game_project_type } = toRefs<any>(proxy?.useDict('game_project_type'));
|
|
|
const router = useRouter();
|
|
|
|
|
|
// 默认赛事信息
|
|
|
-const defaultEvent = ref<GameEventVO>({} as GameEventVO)
|
|
|
+// const defaultEvent = ref<GameEventVO>({} as GameEventVO)
|
|
|
+const gameEventStore = useGameEventStore();
|
|
|
const gameScoreList = ref<GameScoreVO[]>([]);
|
|
|
|
|
|
const buttonLoading = ref(false);
|
|
@@ -140,7 +138,7 @@ const columns = ref<FieldOption[]>([
|
|
|
{ key: 3, label: '归类', visible: true },
|
|
|
{ key: 4, label: '状态', visible: true },
|
|
|
{ key: 5, label: '比赛时间', visible: true },
|
|
|
- { key: 6, label: '更新时间', visible: true },
|
|
|
+ { key: 6, label: '更新时间', visible: true }
|
|
|
]);
|
|
|
|
|
|
// 下拉框数据
|
|
@@ -165,9 +163,9 @@ const initFormData: GameScoreForm = {
|
|
|
statusFlag: undefined,
|
|
|
status: undefined,
|
|
|
remark: undefined
|
|
|
-}
|
|
|
+};
|
|
|
const data = reactive<PageData<GameScoreForm, GameScoreQuery>>({
|
|
|
- form: {...initFormData},
|
|
|
+ form: { ...initFormData },
|
|
|
queryParams: {
|
|
|
pageNum: 1,
|
|
|
pageSize: 10,
|
|
@@ -179,113 +177,404 @@ const data = reactive<PageData<GameScoreForm, GameScoreQuery>>({
|
|
|
});
|
|
|
|
|
|
const { queryParams, form, rules } = toRefs(data);
|
|
|
-// 添加额外的ref用于处理默认事件ID
|
|
|
-const defaultEventId = computed(() => defaultEvent.value?.eventId);
|
|
|
-
|
|
|
-// 监听默认事件变化
|
|
|
-watchEffect(() => {
|
|
|
- if (defaultEventId.value) {
|
|
|
- form.value.eventId = defaultEventId.value;
|
|
|
- queryParams.value.eventId = defaultEventId.value;
|
|
|
- }
|
|
|
-});
|
|
|
-
|
|
|
-// 获取默认赛事
|
|
|
-const getDefaultEventInfo = async () => {
|
|
|
- try {
|
|
|
- const res = await getDefaultEvent()
|
|
|
- defaultEvent.value = res.data
|
|
|
- } catch (error) {
|
|
|
- ElMessage.error('获取默认赛事失败')
|
|
|
- }
|
|
|
-}
|
|
|
|
|
|
/** 查询成绩列表 */
|
|
|
const getList = async () => {
|
|
|
- if (!queryParams.value.eventId) {
|
|
|
- proxy?.$modal.msgWarning('未指定默认赛事');
|
|
|
- loading.value = false;
|
|
|
- return;
|
|
|
- }
|
|
|
- // loading.value = true;
|
|
|
+ // if (!queryParams.value.eventId) {
|
|
|
+ // proxy?.$modal.msgWarning('未指定默认赛事');
|
|
|
+ // loading.value = false;
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+ loading.value = true;
|
|
|
const res = await listGameScore(queryParams.value);
|
|
|
gameScoreList.value = res.rows;
|
|
|
total.value = res.total;
|
|
|
loading.value = false;
|
|
|
-}
|
|
|
-
|
|
|
-/** 查询所有赛事列表 */
|
|
|
-// const getEventList = async () => {
|
|
|
-// const res = await listGameEvent({
|
|
|
-// // status: '0', // 只查询正常状态的赛事
|
|
|
-// pageNum: 1,
|
|
|
-// pageSize: 1000
|
|
|
-// } as GameEventQuery);
|
|
|
-// eventList.value = res.rows;
|
|
|
-
|
|
|
-// // 如果有赛事数据,默认选择第一个
|
|
|
-// if (res.rows && res.rows.length > 0) {
|
|
|
-// queryParams.value.eventId = res.rows[0].eventId;
|
|
|
-// // 触发赛事变更事件,加载相关项目、队伍、运动员数据
|
|
|
-// handleEventChange(queryParams.value.eventId);
|
|
|
-// await getScoreStatus(queryParams.value.projectId);
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-/** 根据赛事ID查询项目列表 */
|
|
|
-// const getProjectList = async (eventId?: string | number) => {
|
|
|
-// if (!eventId) return;
|
|
|
-// const res = await listGameEventProject({
|
|
|
-// eventId: eventId,
|
|
|
-// // status: '0', // 只查询正常状态的项目
|
|
|
-// pageNum: 1,
|
|
|
-// pageSize: 1000
|
|
|
-// } as GameEventProjectQuery);
|
|
|
-// projectList.value = res.rows;
|
|
|
-// }
|
|
|
-
|
|
|
-
|
|
|
-/** 赛事变更事件 */
|
|
|
-// const handleEventChange = async (eventId: string | number | undefined) => {
|
|
|
-// if (!eventId) {
|
|
|
-// // 清空相关下拉框数据
|
|
|
-// projectList.value = [];
|
|
|
-// return;
|
|
|
-// }
|
|
|
-
|
|
|
-// // 加载相关数据
|
|
|
-// await Promise.all([
|
|
|
-// getProjectList(eventId),
|
|
|
-// ]);
|
|
|
-// }
|
|
|
-
|
|
|
-// const getScoreStatus = async (projectId: string | number) => {
|
|
|
-// const score = await listGameScore({
|
|
|
-// projectId: projectId,
|
|
|
-// pageNum: 1,
|
|
|
-// pageSize: 100
|
|
|
-// });
|
|
|
-// if (!score || !score.rows.length) {
|
|
|
-// return '0';
|
|
|
-// }
|
|
|
-// return '1';
|
|
|
-// };
|
|
|
+};
|
|
|
+
|
|
|
/**
|
|
|
* 刷新数据
|
|
|
*/
|
|
|
const refreshData = async () => {
|
|
|
await loadProjects();
|
|
|
};
|
|
|
+// 打印成绩
|
|
|
const printScores = async () => {
|
|
|
- console.log('打印成绩逻辑待实现');
|
|
|
- // await loadProjects();
|
|
|
+ try {
|
|
|
+ // 显示加载状态
|
|
|
+ const loadingInstance = ElLoading.service({
|
|
|
+ lock: true,
|
|
|
+ text: '正在准备打印数据...',
|
|
|
+ background: 'rgba(0, 0, 0, 0.7)'
|
|
|
+ });
|
|
|
+
|
|
|
+ let projectsToPrint = [];
|
|
|
+
|
|
|
+ // 如果有选择项目,则打印选中的项目
|
|
|
+ if (ids.value.length > 0) {
|
|
|
+ projectsToPrint = projectList.value.filter((project) => ids.value.includes(project.projectId));
|
|
|
+ } else {
|
|
|
+ // 如果没有选择项目,提示用户是否打印所有项目
|
|
|
+ try {
|
|
|
+ await proxy?.$modal.confirm('未选择项目,是否打印当前页面所有项目?');
|
|
|
+ projectsToPrint = [...projectList.value];
|
|
|
+ } catch {
|
|
|
+ // 用户取消操作
|
|
|
+ loadingInstance.close();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (projectsToPrint.length === 0) {
|
|
|
+ proxy?.$modal.msgWarning('没有可打印的项目');
|
|
|
+ loadingInstance.close();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 为每个项目获取成绩数据
|
|
|
+ const projectsWithScores = await Promise.all(
|
|
|
+ projectsToPrint.map(async (project) => {
|
|
|
+ try {
|
|
|
+ const scoreRes = await getProjectScoreData({
|
|
|
+ eventId: project.eventId,
|
|
|
+ projectId: project.projectId,
|
|
|
+ classification: project.classification,
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 1000
|
|
|
+ });
|
|
|
+
|
|
|
+ // 获取成绩数据并补充队伍和运动员信息
|
|
|
+ const scores = scoreRes.rows || [];
|
|
|
+
|
|
|
+ // 按积分排序,取前3名
|
|
|
+ const sortedScores = scores
|
|
|
+ .filter((score) => score.scorePoint && score.scorePoint > 0) // 只显示有积分的成绩
|
|
|
+ .sort((a: any, b: any) => (b.scorePoint || 0) - (a.scorePoint || 0)) // 按积分降序排列
|
|
|
+ .slice(0, 3); // 只取前3名
|
|
|
+
|
|
|
+ const scoresWithDetails = await Promise.all(
|
|
|
+ sortedScores.map(async (score: any) => {
|
|
|
+ let teamName = '-';
|
|
|
+ let athleteName = '-';
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 获取队伍信息
|
|
|
+ if (score.teamId) {
|
|
|
+ const teamRes = await getGameTeam(score.teamId);
|
|
|
+ teamName = teamRes.data.teamName || `队伍${score.teamId}`;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 获取运动员信息
|
|
|
+ if (score.athleteId) {
|
|
|
+ const athleteRes = await getGameAthlete(score.athleteId);
|
|
|
+ athleteName = athleteRes.data.name || `运动员${score.athleteId}`;
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ console.warn('获取队伍或运动员信息失败:', error);
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...score,
|
|
|
+ teamName,
|
|
|
+ athleteName
|
|
|
+ };
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ return {
|
|
|
+ ...project,
|
|
|
+ scores: scoresWithDetails
|
|
|
+ };
|
|
|
+ } catch (error) {
|
|
|
+ console.error(`获取项目 ${project.projectName} 成绩失败:`, error);
|
|
|
+ return {
|
|
|
+ ...project,
|
|
|
+ scores: []
|
|
|
+ };
|
|
|
+ }
|
|
|
+ })
|
|
|
+ );
|
|
|
+
|
|
|
+ // 关闭加载状态
|
|
|
+ loadingInstance.close();
|
|
|
+
|
|
|
+ // 构建打印HTML内容
|
|
|
+ const printHtml = buildPrintHtml(projectsWithScores);
|
|
|
+
|
|
|
+ // 使用 Blob 和 URL.createObjectURL 来避免弹窗拦截问题
|
|
|
+ const blob = new Blob([printHtml], { type: 'text/html' });
|
|
|
+ const url = URL.createObjectURL(blob);
|
|
|
+
|
|
|
+ // 创建隐藏的 iframe 来处理打印
|
|
|
+ const iframe = document.createElement('iframe');
|
|
|
+ iframe.style.position = 'absolute';
|
|
|
+ iframe.style.top = '-9999px';
|
|
|
+ iframe.style.left = '-9999px';
|
|
|
+ document.body.appendChild(iframe);
|
|
|
+
|
|
|
+ iframe.onload = () => {
|
|
|
+ try {
|
|
|
+ // 打印完成后清理
|
|
|
+ setTimeout(() => {
|
|
|
+ document.body.removeChild(iframe);
|
|
|
+ URL.revokeObjectURL(url);
|
|
|
+ }, 1000);
|
|
|
+ } catch (error) {
|
|
|
+ console.error('清理打印资源失败:', error);
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ // 在 iframe 中加载并打印
|
|
|
+ const iframeDoc = iframe.contentDocument || iframe.contentWindow?.document;
|
|
|
+ if (iframeDoc) {
|
|
|
+ iframeDoc.open();
|
|
|
+ iframeDoc.write(printHtml);
|
|
|
+ iframeDoc.close();
|
|
|
+
|
|
|
+ // 等待内容加载后打印
|
|
|
+ setTimeout(() => {
|
|
|
+ try {
|
|
|
+ iframe.contentWindow?.focus();
|
|
|
+ iframe.contentWindow?.print();
|
|
|
+ } catch (error) {
|
|
|
+ proxy?.$modal.msgError('打印失败,请检查浏览器设置');
|
|
|
+ console.error('打印失败:', error);
|
|
|
+ }
|
|
|
+ }, 500);
|
|
|
+ } else {
|
|
|
+ proxy?.$modal.msgError('无法创建打印窗口,请检查浏览器设置');
|
|
|
+ document.body.removeChild(iframe);
|
|
|
+ URL.revokeObjectURL(url);
|
|
|
+ }
|
|
|
+ } catch (error) {
|
|
|
+ if (error === 'cancel') {
|
|
|
+ // 用户取消操作
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ console.error('打印失败:', error);
|
|
|
+ proxy?.$modal.msgError('打印失败');
|
|
|
+ }
|
|
|
};
|
|
|
-const exportNumberMapping = async () => {
|
|
|
- console.log('导出号码对照表逻辑待实现');
|
|
|
- // await loadProjects();
|
|
|
+
|
|
|
+/**
|
|
|
+ * 构建打印HTML内容
|
|
|
+ */
|
|
|
+const buildPrintHtml = (projects: any[]) => {
|
|
|
+ const printTime = new Date().toLocaleString('zh-CN');
|
|
|
+
|
|
|
+ let html = `
|
|
|
+ <!DOCTYPE html>
|
|
|
+ <html>
|
|
|
+ <head>
|
|
|
+ <meta charset="UTF-8">
|
|
|
+ <title>赛事成绩打印 - 前3名</title>
|
|
|
+ <style>
|
|
|
+ body { font-family: Arial, sans-serif; margin: 20px; }
|
|
|
+ .print-header { text-align: center; margin-bottom: 30px; border-bottom: 2px solid #333; padding-bottom: 20px; }
|
|
|
+ .print-header h1 { margin: 0 0 10px 0; font-size: 24px; color: #333; }
|
|
|
+ .print-header p { margin: 0; color: #666; font-size: 14px; }
|
|
|
+ .project-section { margin-bottom: 40px; page-break-inside: avoid; }
|
|
|
+ .project-title { font-size: 18px; font-weight: bold; margin-bottom: 15px; padding: 10px; background: #f5f5f5; border-left: 4px solid #409eff; }
|
|
|
+ .title-label { color: #f56c6c; font-weight: bold; }
|
|
|
+ .score-table { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
|
|
|
+ .score-table th, .score-table td { border: 1px solid #ddd; padding: 8px 12px; text-align: center; }
|
|
|
+ .score-table th { background: #f8f9fa; font-weight: bold; color: #333; }
|
|
|
+ .score-table td { color: #333; }
|
|
|
+ .rank-1 { background-color: #fff7e6; font-weight: bold; }
|
|
|
+ .rank-2 { background-color: #f6ffed; }
|
|
|
+ .rank-3 { background-color: #f0f9ff; }
|
|
|
+ @media print { .project-section { page-break-inside: avoid; } }
|
|
|
+ </style>
|
|
|
+ </head>
|
|
|
+ <body>
|
|
|
+ <div class="print-header">
|
|
|
+ <h1>赛事管理系统 - 成绩打印(前3名)</h1>
|
|
|
+ <p>打印时间: ${printTime}</p>
|
|
|
+ </div>
|
|
|
+ `;
|
|
|
+
|
|
|
+ // 为每个项目添加成绩表格
|
|
|
+ projects.forEach((project) => {
|
|
|
+ const scores = project.scores || [];
|
|
|
+
|
|
|
+ html += `
|
|
|
+ <div class="project-section">
|
|
|
+ <div class="project-title">
|
|
|
+ <span class="title-label">${project.projectId}</span>
|
|
|
+ <span class="title-label">${getProjectTypeName(project.projectType)} ${project.projectName}</span>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <table class="score-table">
|
|
|
+ <thead>
|
|
|
+ <tr>
|
|
|
+ <th class="title-label">类别</th>
|
|
|
+ <th>名次</th>
|
|
|
+ <th class="title-label">队伍</th>
|
|
|
+ <th class="title-label">运动员编号</th>
|
|
|
+ <th class="title-label">姓名</th>
|
|
|
+ <th class="title-label">成绩</th>
|
|
|
+ <th class="title-label">积分</th>
|
|
|
+ </tr>
|
|
|
+ </thead>
|
|
|
+ <tbody>
|
|
|
+ `;
|
|
|
+
|
|
|
+ if (scores.length > 0) {
|
|
|
+ scores.forEach((score: any, index: number) => {
|
|
|
+ const rankClass = index === 0 ? 'rank-1' : index === 1 ? 'rank-2' : 'rank-3';
|
|
|
+ html += `
|
|
|
+ <tr class="${rankClass}">
|
|
|
+ <td>${score.classification === '0' ? '个人项目' : '团体项目'}</td>
|
|
|
+ <td>第${index + 1}名</td>
|
|
|
+ <td>${score.teamName || '-'}</td>
|
|
|
+ <td>${score.athleteId || '-'}</td>
|
|
|
+ <td>${score.athleteName || '-'}</td>
|
|
|
+ <td>${formatScore(score.individualPerformance || score.teamPerformance)}</td>
|
|
|
+ <td>${score.scorePoint || 0}</td>
|
|
|
+ </tr>
|
|
|
+ `;
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ html += `
|
|
|
+ <tr>
|
|
|
+ <td colspan="7" style="text-align: center; color: #999;">暂无成绩数据</td>
|
|
|
+ </tr>
|
|
|
+ `;
|
|
|
+ }
|
|
|
+
|
|
|
+ html += `
|
|
|
+ </tbody>
|
|
|
+ </table>
|
|
|
+ </div>
|
|
|
+ `;
|
|
|
+ });
|
|
|
+
|
|
|
+ html += `
|
|
|
+ </body>
|
|
|
+ </html>
|
|
|
+ `;
|
|
|
+
|
|
|
+ return html;
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 格式化成绩显示
|
|
|
+ */
|
|
|
+const formatScore = (score: number | string) => {
|
|
|
+ if (score === null || score === undefined || score === '') return '-';
|
|
|
+ return score.toString();
|
|
|
+};
|
|
|
+
|
|
|
+/**
|
|
|
+ * 获取项目类型名称
|
|
|
+ */
|
|
|
+const getProjectTypeName = (type: string) => {
|
|
|
+ const typeMap: Record<string, string> = {
|
|
|
+ '1': '田径',
|
|
|
+ '2': '游泳',
|
|
|
+ '3': '球类',
|
|
|
+ '4': '其他'
|
|
|
+ };
|
|
|
+ return typeMap[type] || '未知';
|
|
|
};
|
|
|
-const exportScoresNames = async () => {
|
|
|
- console.log('导出成绩逻辑待实现');
|
|
|
+
|
|
|
+const exportScoresNames = async () => {
|
|
|
+ try {
|
|
|
+ // 显示加载状态
|
|
|
+ const loadingInstance = ElLoading.service({
|
|
|
+ lock: true,
|
|
|
+ text: '正在导出成绩汇总表...',
|
|
|
+ background: 'rgba(0, 0, 0, 0.7)'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 获取默认赛事ID
|
|
|
+ const event = gameEventStore.defaultEventInfo;
|
|
|
+ const eventId = event?.eventId;
|
|
|
+
|
|
|
+ if (!eventId) {
|
|
|
+ proxy?.$modal.msgWarning('未指定赛事,无法导出');
|
|
|
+ loadingInstance.close();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 调用导出接口
|
|
|
+ const response = await exportScoresSummary(eventId);
|
|
|
+
|
|
|
+ // 校验响应是否为有效的二进制数据
|
|
|
+ if (!response || !response.data || !(response.data instanceof Blob)) {
|
|
|
+ proxy?.$modal.msgError('导出失败:服务器返回数据异常');
|
|
|
+ loadingInstance.close();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 创建Blob时,明确指定类型
|
|
|
+ const blob = new Blob([response.data], {
|
|
|
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
|
+ });
|
|
|
+
|
|
|
+ // 验证Blob大小是否合理(防止空文件)
|
|
|
+ if (blob.size === 0) {
|
|
|
+ proxy?.$modal.msgError('导出失败:生成的文件为空');
|
|
|
+ loadingInstance.close();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ const url = window.URL.createObjectURL(blob);
|
|
|
+ const link = document.createElement('a');
|
|
|
+ link.href = url;
|
|
|
+ link.download = `成绩汇总表_${new Date().toLocaleDateString()}.xlsx`;
|
|
|
+ document.body.appendChild(link);
|
|
|
+ link.click();
|
|
|
+ document.body.removeChild(link);
|
|
|
+ window.URL.revokeObjectURL(url);
|
|
|
+
|
|
|
+ loadingInstance.close();
|
|
|
+ proxy?.$modal.msgSuccess('导出成功');
|
|
|
+ } catch (error) {
|
|
|
+ console.error('导出失败:', error);
|
|
|
+ let errorMessage = '未知错误';
|
|
|
+
|
|
|
+ if (error instanceof Error) {
|
|
|
+ errorMessage = error.message;
|
|
|
+ } else if (typeof error === 'string') {
|
|
|
+ errorMessage = error;
|
|
|
+ } else if (error && typeof error === 'object' && 'message' in error) {
|
|
|
+ errorMessage = String(error.message);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 尝试获取更详细的错误信息
|
|
|
+ if (error && typeof error === 'object' && 'response' in error) {
|
|
|
+ const response = (error as any).response;
|
|
|
+ if (response && response.data) {
|
|
|
+ try {
|
|
|
+ if (response.data instanceof Blob) {
|
|
|
+ // 如果是blob,尝试读取错误信息
|
|
|
+ const reader = new FileReader();
|
|
|
+ reader.onload = function (e) {
|
|
|
+ try {
|
|
|
+ const text = e.target?.result as string;
|
|
|
+ const errorObj = JSON.parse(text);
|
|
|
+ if (errorObj.msg) {
|
|
|
+ errorMessage = errorObj.msg;
|
|
|
+ }
|
|
|
+ } catch (parseError) {
|
|
|
+ console.warn('无法解析错误响应:', parseError);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ reader.readAsText(response.data);
|
|
|
+ } else if (typeof response.data === 'string') {
|
|
|
+ errorMessage = response.data;
|
|
|
+ } else if (response.data.msg) {
|
|
|
+ errorMessage = response.data.msg;
|
|
|
+ }
|
|
|
+ } catch (parseError) {
|
|
|
+ console.warn('解析错误响应失败:', parseError);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ proxy?.$modal.msgError('导出失败:' + errorMessage);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
/**
|
|
@@ -293,7 +582,7 @@ const exportScoresNames = async () => {
|
|
|
*/
|
|
|
const loadProjects = async () => {
|
|
|
loading.value = true;
|
|
|
- console.log('加载项目列表: ',queryParams.value);
|
|
|
+ console.log('加载项目列表: ', queryParams.value);
|
|
|
const res = await listGameEventProject(queryParams.value);
|
|
|
projectList.value = res.rows;
|
|
|
total.value = res.total;
|
|
@@ -308,16 +597,16 @@ const handleQuery = () => {
|
|
|
const resetQuery = () => {
|
|
|
queryFormRef.value?.resetFields();
|
|
|
// 保留默认赛事ID
|
|
|
- queryParams.value.eventId = defaultEvent.value?.eventId;
|
|
|
+ // queryParams.value.eventId = defaultEvent.value?.eventId;
|
|
|
handleQuery();
|
|
|
};
|
|
|
|
|
|
/** 多选框选中数据 */
|
|
|
const handleSelectionChange = (selection: GameScoreVO[]) => {
|
|
|
- ids.value = selection.map(item => item.projectId); // 使用eventId作为标识
|
|
|
+ ids.value = selection.map((item) => item.projectId); // 使用eventId作为标识
|
|
|
single.value = selection.length != 1;
|
|
|
multiple.value = !selection.length;
|
|
|
-}
|
|
|
+};
|
|
|
|
|
|
const navigateToEditPage = (row: GameEventProjectVO) => {
|
|
|
const projectId = row.projectId;
|
|
@@ -332,9 +621,9 @@ const navigateToEditPage = (row: GameEventProjectVO) => {
|
|
|
};
|
|
|
|
|
|
onMounted(() => {
|
|
|
- getDefaultEventInfo().then(() => {
|
|
|
- getList();
|
|
|
- refreshData();
|
|
|
- });
|
|
|
+ // getDefaultEventInfo().then(() => {
|
|
|
+ getList();
|
|
|
+ refreshData();
|
|
|
+ // });
|
|
|
});
|
|
|
-</script>
|
|
|
+</script>
|