|
@@ -58,6 +58,24 @@
|
|
|
/>
|
|
/>
|
|
|
<span class="control-label">名</span>
|
|
<span class="control-label">名</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="success"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ :icon="Download"
|
|
|
|
|
+ @click="exportPersonalRanking"
|
|
|
|
|
+ class="export-btn"
|
|
|
|
|
+ >
|
|
|
|
|
+ 导出
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="warning"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ :icon="Printer"
|
|
|
|
|
+ @click="printPersonalRanking"
|
|
|
|
|
+ class="print-btn"
|
|
|
|
|
+ >
|
|
|
|
|
+ 打印
|
|
|
|
|
+ </el-button>
|
|
|
<el-button
|
|
<el-button
|
|
|
type="primary"
|
|
type="primary"
|
|
|
size="small"
|
|
size="small"
|
|
@@ -152,6 +170,24 @@
|
|
|
/>
|
|
/>
|
|
|
<span class="control-label">名</span>
|
|
<span class="control-label">名</span>
|
|
|
</div>
|
|
</div>
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="success"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ :icon="Download"
|
|
|
|
|
+ @click="exportTeamRanking"
|
|
|
|
|
+ class="export-btn"
|
|
|
|
|
+ >
|
|
|
|
|
+ 导出
|
|
|
|
|
+ </el-button>
|
|
|
|
|
+ <el-button
|
|
|
|
|
+ type="warning"
|
|
|
|
|
+ size="small"
|
|
|
|
|
+ :icon="Printer"
|
|
|
|
|
+ @click="printTeamRanking"
|
|
|
|
|
+ class="print-btn"
|
|
|
|
|
+ >
|
|
|
|
|
+ 打印
|
|
|
|
|
+ </el-button>
|
|
|
<el-button
|
|
<el-button
|
|
|
type="primary"
|
|
type="primary"
|
|
|
size="small"
|
|
size="small"
|
|
@@ -205,7 +241,8 @@ import { useGameEventStore } from '@/store/modules/gameEvent';
|
|
|
import { storeToRefs } from 'pinia';
|
|
import { storeToRefs } from 'pinia';
|
|
|
import { listRankGroup } from '@/api/system/rankGroup';
|
|
import { listRankGroup } from '@/api/system/rankGroup';
|
|
|
import { RankGroupVO } from '@/api/system/rankGroup/types';
|
|
import { RankGroupVO } from '@/api/system/rankGroup/types';
|
|
|
-import { Refresh } from '@element-plus/icons-vue';
|
|
|
|
|
|
|
+import { Refresh, Download, Printer } from '@element-plus/icons-vue';
|
|
|
|
|
+import { saveAs } from 'file-saver';
|
|
|
|
|
|
|
|
// 定义队伍积分排行榜的数据结构
|
|
// 定义队伍积分排行榜的数据结构
|
|
|
interface TeamScore {
|
|
interface TeamScore {
|
|
@@ -605,6 +642,205 @@ const refreshPersonalRanking = async () => {
|
|
|
}
|
|
}
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
|
|
+// 导出个人排行榜
|
|
|
|
|
+const exportPersonalRanking = async () => {
|
|
|
|
|
+ if (athleteScoreList.value.length === 0) {
|
|
|
|
|
+ ElMessage.warning('没有可导出的数据');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const { value } = await ElMessageBox.prompt('请输入导出前几名(不输入则导出全部)', '导出确认', {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ inputPattern: /^\d*$/,
|
|
|
|
|
+ inputErrorMessage: '请输入数字'
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const count = value ? parseInt(value) : athleteScoreList.value.length;
|
|
|
|
|
+ const exportData = athleteScoreList.value.slice(0, count);
|
|
|
|
|
+
|
|
|
|
|
+ const columns = ['排名', '姓名', '队伍名称', '项目', '成绩'];
|
|
|
|
|
+ const csvContent = exportData.map((item, index) => {
|
|
|
|
|
+ const rank = getRankDisplay(item, index, athleteScoreList.value);
|
|
|
|
|
+ const name = item.name || item.athleteName || '';
|
|
|
|
|
+ const team = item.teamName || '';
|
|
|
|
|
+ const project = selectedProjectName.value;
|
|
|
|
|
+ // 在成绩前加 \t 防止 Excel 自动转换格式
|
|
|
|
|
+ const scoreValue = item.individualPerformance || item.score || item.totalScore || '';
|
|
|
|
|
+ const score = `\t${scoreValue}`;
|
|
|
|
|
+ return [rank, name, team, project, score].join(',');
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const blob = new Blob(['\ufeff' + columns.join(',') + '\n' + csvContent.join('\n')], { type: 'text/csv;charset=utf-8;' });
|
|
|
|
|
+ saveAs(blob, `${selectedProjectName.value}_个人排行榜.csv`);
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ // 点击取消不执行
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 打印个人排行榜
|
|
|
|
|
+const printPersonalRanking = async () => {
|
|
|
|
|
+ if (athleteScoreList.value.length === 0) {
|
|
|
|
|
+ ElMessage.warning('没有可打印的数据');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const { value } = await ElMessageBox.prompt('请输入打印前几名(不输入则打印全部)', '打印确认', {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ inputPattern: /^\d*$/,
|
|
|
|
|
+ inputErrorMessage: '请输入数字'
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const count = value ? parseInt(value) : athleteScoreList.value.length;
|
|
|
|
|
+ const printData = athleteScoreList.value.slice(0, count);
|
|
|
|
|
+
|
|
|
|
|
+ const title = `${selectedProjectName.value} - 个人排行榜`;
|
|
|
|
|
+ const columns = ['排名', '姓名', '队伍名称', '项目', '成绩'];
|
|
|
|
|
+ const rows = printData.map((item, index) => {
|
|
|
|
|
+ const rank = getRankDisplay(item, index, athleteScoreList.value);
|
|
|
|
|
+ const name = item.name || item.athleteName || '';
|
|
|
|
|
+ const team = item.teamName || '';
|
|
|
|
|
+ const project = selectedProjectName.value;
|
|
|
|
|
+ const score = item.individualPerformance || item.score || item.totalScore || '';
|
|
|
|
|
+ return [rank, name, team, project, score];
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ generatePrintPage(title, columns, rows);
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ // 取消
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 导出团队排行榜
|
|
|
|
|
+const exportTeamRanking = async () => {
|
|
|
|
|
+ if (filteredTeamScores.value.length === 0) {
|
|
|
|
|
+ ElMessage.warning('没有可导出的数据');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const { value } = await ElMessageBox.prompt('请输入导出前几名(不输入则导出全部)', '导出确认', {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ inputPattern: /^\d*$/,
|
|
|
|
|
+ inputErrorMessage: '请输入数字'
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const count = value ? parseInt(value) : filteredTeamScores.value.length;
|
|
|
|
|
+ const exportData = filteredTeamScores.value.slice(0, count);
|
|
|
|
|
+
|
|
|
|
|
+ const columns = ['排名', '项目', '队伍名称', '组别', '成绩'];
|
|
|
|
|
+ const csvContent = exportData.map((item, index) => {
|
|
|
|
|
+ const rank = getRankDisplay(item, index, filteredTeamScores.value);
|
|
|
|
|
+ const project = selectedTeamProjectName.value;
|
|
|
|
|
+ const teamName = item.name || item.teamName || '';
|
|
|
|
|
+ const groupName = item.rgName || '-';
|
|
|
|
|
+ const scoreValue = item.teamPerformance || item.score || item.totalScore || '';
|
|
|
|
|
+ const score = `\t${scoreValue}`;
|
|
|
|
|
+ return [rank, project, teamName, groupName, score].join(',');
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const blob = new Blob(['\ufeff' + columns.join(',') + '\n' + csvContent.join('\n')], { type: 'text/csv;charset=utf-8;' });
|
|
|
|
|
+ saveAs(blob, `${selectedTeamProjectName.value}_团队排行榜.csv`);
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ // 取消
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 打印团队排行榜
|
|
|
|
|
+const printTeamRanking = async () => {
|
|
|
|
|
+ if (filteredTeamScores.value.length === 0) {
|
|
|
|
|
+ ElMessage.warning('没有可打印的数据');
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ try {
|
|
|
|
|
+ const { value } = await ElMessageBox.prompt('请输入打印前几名(不输入则打印全部)', '打印确认', {
|
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
|
+ inputPattern: /^\d*$/,
|
|
|
|
|
+ inputErrorMessage: '请输入数字'
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ const count = value ? parseInt(value) : filteredTeamScores.value.length;
|
|
|
|
|
+ const printData = filteredTeamScores.value.slice(0, count);
|
|
|
|
|
+
|
|
|
|
|
+ const title = `${selectedTeamProjectName.value} - 团队排行榜`;
|
|
|
|
|
+ const columns = ['排名', '项目', '队伍名称', '组别', '成绩'];
|
|
|
|
|
+ const rows = printData.map((item, index) => {
|
|
|
|
|
+ const rank = getRankDisplay(item, index, filteredTeamScores.value);
|
|
|
|
|
+ const project = selectedTeamProjectName.value;
|
|
|
|
|
+ const teamName = item.name || item.teamName || '';
|
|
|
|
|
+ const groupName = item.rgName || '-';
|
|
|
|
|
+ const score = item.teamPerformance || item.score || item.totalScore || '';
|
|
|
|
|
+ return [rank, project, teamName, groupName, score];
|
|
|
|
|
+ });
|
|
|
|
|
+
|
|
|
|
|
+ generatePrintPage(title, columns, rows);
|
|
|
|
|
+ } catch (e) {
|
|
|
|
|
+ // 取消
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 通用打印页面生成函数
|
|
|
|
|
+const generatePrintPage = (title, columns, rows) => {
|
|
|
|
|
+ const printWindow = window.open('', '_blank');
|
|
|
|
|
+ if (!printWindow) return;
|
|
|
|
|
+
|
|
|
|
|
+ const tableHtml = `
|
|
|
|
|
+ <table border="1" style="width:100%; border-collapse: collapse; margin-top: 20px;">
|
|
|
|
|
+ <thead>
|
|
|
|
|
+ <tr style="background-color: #f5f7fa;">
|
|
|
|
|
+ ${columns.map(col => `<th style="padding: 10px; border: 1px solid #ddd;">${col}</th>`).join('')}
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ </thead>
|
|
|
|
|
+ <tbody>
|
|
|
|
|
+ ${rows.map(row => `
|
|
|
|
|
+ <tr>
|
|
|
|
|
+ ${row.map(cell => `<td style="padding: 10px; border: 1px solid #ddd; text-align: center;">${cell}</td>`).join('')}
|
|
|
|
|
+ </tr>
|
|
|
|
|
+ `).join('')}
|
|
|
|
|
+ </tbody>
|
|
|
|
|
+ </table>
|
|
|
|
|
+ `;
|
|
|
|
|
+
|
|
|
|
|
+ printWindow.document.write(`
|
|
|
|
|
+ <!DOCTYPE html>
|
|
|
|
|
+ <html>
|
|
|
|
|
+ <head>
|
|
|
|
|
+ <meta charset="utf-8">
|
|
|
|
|
+ <title>${title}</title>
|
|
|
|
|
+ <style>
|
|
|
|
|
+ body { font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif; color: #333; padding: 20px; }
|
|
|
|
|
+ h1 { text-align: center; color: #303133; margin-bottom: 30px; }
|
|
|
|
|
+ .print-time { text-align: right; color: #909399; font-size: 14px; margin-bottom: 10px; }
|
|
|
|
|
+ @media print {
|
|
|
|
|
+ @page { margin: 1cm; }
|
|
|
|
|
+ button { display: none; }
|
|
|
|
|
+ }
|
|
|
|
|
+ </style>
|
|
|
|
|
+ </head>
|
|
|
|
|
+ <body>
|
|
|
|
|
+ <h1>${title}</h1>
|
|
|
|
|
+ <div class="print-time">打印时间:${new Date().toLocaleString()}</div>
|
|
|
|
|
+ ${tableHtml}
|
|
|
|
|
+ <script>
|
|
|
|
|
+ window.onload = function() {
|
|
|
|
|
+ setTimeout(function() {
|
|
|
|
|
+ window.print();
|
|
|
|
|
+ // window.close(); // 打印完自动关闭可选
|
|
|
|
|
+ }, 500);
|
|
|
|
|
+ };
|
|
|
|
|
+ <\/script>
|
|
|
|
|
+ </body>
|
|
|
|
|
+ </html>
|
|
|
|
|
+ `);
|
|
|
|
|
+ printWindow.document.close();
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
// 刷新团队排行榜数据
|
|
// 刷新团队排行榜数据
|
|
|
const refreshTeamRanking = async () => {
|
|
const refreshTeamRanking = async () => {
|
|
|
teamRefreshing.value = true;
|
|
teamRefreshing.value = true;
|