5 コミット 06a901d23c ... c57f13fa89

作者 SHA1 メッセージ 日付
  zhou c57f13fa89 ``` 3 ヶ月 前
  zhou 9dce32d699 ``` 3 ヶ月 前
  zhou c1887662f2 ``` 3 ヶ月 前
  zhou 2a46c12cd3 feat(gameEvent): 更新页面文案以提升表达准确性 4 ヶ月 前
  zhou f62f27a014 feat(system): 修改赛事管理权限控制和运动员列表展示 4 ヶ月 前

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

@@ -26,12 +26,12 @@ export interface GameScoreVO {
   /**
    * 个人成绩
    */
-  individualPerformance: number;
+  individualPerformance: string;
 
   /**
    * 团队成绩
    */
-  teamPerformance: number;
+  teamPerformance: string;
 
   /**
    * 成绩类型

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

@@ -69,7 +69,7 @@
             {{ formatProjectList(scope.row.projectList) }}
           </template>
         </el-table-column>
-        <el-table-column label="证件号" align="center" prop="idCard" v-if="columns[7].visible" />
+        <!-- <el-table-column label="证件号" align="center" prop="idCard" v-if="columns[7].visible" /> -->
         <el-table-column label="队伍" align="center" prop="teamId" v-if="columns[8].visible">
           <template #default="scope">
             {{ getTeamNameById(scope.row.teamId) }}

+ 1 - 1
src/views/system/gameEvent/RankingBoardPage.vue

@@ -25,7 +25,7 @@
               <div class="personal-ranking-header">
                 <!-- 标题单独一行,居中对齐 -->
                 <div class="header-title">
-                  <span>个人积分排行榜</span>
+                  <span>个人项目排行榜</span>
                 </div>
                 <!-- 控件在一行,均匀分布 -->
                 <div class="header-controls">

+ 3 - 3
src/views/system/gameEvent/index.vue

@@ -52,7 +52,7 @@
           <!-- 新增的操作按钮,基于默认赛事 -->
           <el-col :span="1.5">
             <el-button type="warning" plain icon="Download" @click="handleDownloadTemplateDefault" v-hasPermi="['system:gameEvent:download']"
-              >下载报名表
+              >下载报名表模板
             </el-button>
           </el-col>
           <el-col :span="1.5">
@@ -90,7 +90,7 @@
           </el-col>
           <el-col :span="1.5">
             <el-button type="success" plain icon="Postcard" @click="handleGenerateBib" v-hasPermi="['system:gameEvent:numberBib']"
-              >生成参赛
+              >生成参赛号码布
             </el-button>
           </el-col>
           <!-- <el-col :span="1.5">
@@ -154,7 +154,7 @@
         <el-table-column label="举办单位" align="center" prop="unit" v-if="columns[10].visible" />
         <el-table-column label="是否默认赛事" align="center" prop="isDefault" v-if="columns[11].visible">
           <template #default="scope">
-            <el-switch v-model="scope.row.isDefault" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
+            <el-switch v-model="scope.row.isDefault" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)" v-hasPermi="['system:gameEvent:edit']"></el-switch>
           </template>
         </el-table-column>
         <el-table-column label="创建时间" align="center" prop="createTime" width="180" v-if="columns[12].visible">

+ 223 - 91
src/views/system/gameScore/index.vue

@@ -492,7 +492,7 @@ const printScores = async () => {
 
           // 按积分排序,取前n名(使用用户输入的数量)
           const sortedScores = scores
-            .filter(score => score.scorePoint && score.scorePoint > 0) // 只显示有积分的成绩
+            // .filter(score => score.scorePoint && score.scorePoint > 0) // 只显示有积分的成绩
             .sort((a: any, b: any) => (b.scorePoint || 0) - (a.scorePoint || 0)) // 按积分降序排列
             .slice(0, topCount); // 使用用户输入的数量
 
@@ -606,107 +606,232 @@ const printScores = async () => {
 /**
  * 构建打印HTML内容
  */
-const buildPrintHtml = (projects: any[], topCount: number = 3) => {
-  const printTime = new Date().toLocaleString('zh-CN');
-
-  let html = `
-    <!DOCTYPE html>
+const buildPrintHtml = (projects: any[], topCount: number) => {
+  return `
     <html>
     <head>
       <meta charset="UTF-8">
-      <title>赛事成绩打印 - 前${topCount}名</title>
+      <title>成绩打印(前${topCount}名)</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; }
+        body {
+          font-family: SimSun, 'Times New Roman', serif;
+          padding: 20px;
+          margin: 0;
+          color: #333;
+        }
+        .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;
+        }
+        .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 {
+          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;
+        }
+        .rank-1 { background-color: #fff7e6; }
         .rank-2 { background-color: #f6ffed; }
         .rank-3 { background-color: #f0f9ff; }
-        @media print { .project-section { page-break-inside: avoid; } }
+        
+        /* 打印样式 - 优化打印预览和实际打印效果一致性 */
+        @media print {
+          * {
+            -webkit-print-color-adjust: exact !important;
+            print-color-adjust: exact !important;
+            background: transparent !important;
+            box-shadow: none !important;
+            text-shadow: none !important;
+          }
+          
+          body {
+            font-family: SimSun, "Times New Roman", serif !important;
+            font-size: 12pt !important;
+            line-height: 1.4 !important;
+            color: #000 !important;
+            padding: 0 !important;
+          }
+          
+          .print-container {
+            padding: 0 !important;
+            max-width: 100% !important;
+          }
+          
+          .print-content {
+            width: 100% !important;
+            max-width: 100% !important;
+          }
+          
+          .project-section {
+            page-break-inside: avoid !important;
+            page-break-after: auto !important;
+          }
+          
+          .score-table {
+            width: 100% !important;
+            border-collapse: collapse !important;
+            font-size: 11pt !important;
+            page-break-inside: avoid !important;
+          }
+          
+          .score-table th,
+          .score-table td {
+            border: 1px solid #000 !important;
+            padding: 5pt !important;
+            text-align: center !important;
+            vertical-align: middle !important;
+          }
+          
+          .score-table th {
+            background-color: #f8f9fa !important;
+            color: #000 !important;
+            font-weight: bold !important;
+          }
+          
+          .score-table thead {
+            display: table-header-group !important; /* 确保表头在每页重复 */
+          }
+          
+          .score-table tbody {
+            display: table-row-group !important;
+          }
+          
+          /* 确保排名样式在打印中正确显示 */
+          .rank-1 {
+            background-color: #fff7e6 !important;
+            color: #000 !important;
+          }
+          
+          .rank-2 {
+            background-color: #f6ffed !important;
+            color: #000 !important;
+          }
+          
+          .rank-3 {
+            background-color: #f0f9ff !important;
+            color: #000 !important;
+          }
+          
+          /* 设置页面边距 */
+          @page {
+            margin: 20mm !important;
+            size: A4 !important;
+          }
+          
+          /* 避免第一页顶部和最后一页底部有太多空白 */
+          .print-header {
+            page-break-after: avoid !important;
+            border-bottom: 2px solid #000 !important;
+            margin-bottom: 30pt !important;
+            padding-bottom: 20pt !important;
+          }
+          
+          /* 确保字体大小在打印中保持一致 */
+          h1 {
+            font-size: 18pt !important;
+            margin-bottom: 10pt !important;
+            color: #000 !important;
+          }
+          
+          .project-title {
+            font-size: 14pt !important;
+            margin-bottom: 10pt !important;
+            padding: 8pt !important;
+            border-left: 4px solid #000 !important;
+            background-color: #f5f5f5 !important;
+            color: #000 !important;
+          }
+          
+          .title-label {
+            color: #000 !important;
+          }
+          
+          /* 确保在IE浏览器中也能正常打印 */
+          @media print and (-ms-high-contrast: none), print and (-ms-high-contrast: active) {
+            * {
+              color-adjust: exact !important;
+            }
+          }
+        }
       </style>
     </head>
     <body>
       <div class="print-header">
         <h1>赛事管理系统 - 成绩打印(前${topCount}名)</h1>
-        <p>打印时间: ${printTime}</p>
+        <p>打印时间: ${new Date().toLocaleString('zh-CN')}</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>
+      
+      ${projects.map(project => `
+        <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 class="title-label">名次</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>
+              ${project.scores.slice(0, topCount).map((score: any, index: number) => `
+                <tr>
+                  <td>${score.classification === '0' ? '个人项目' : '团体项目'}</td>
+                  <td>第${Number(index) + 1}名</td>
+                  <td>${score.teamName || '-'}</td>
+                  <td>${score.athleteCode || '-'}</td>
+                  <td>${score.athleteName || '-'}</td>
+                  <td >${score.classification === '0' ? formatScore(score.individualPerformance) : formatScore(score.teamPerformance)}</td>
+                  <td>${score.scorePoint || 0}</td>
+                </tr>
+              `).join('')}
+            </tbody>
+          </table>
         </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) => {
-        // 动态设置排名样式,只对前3名应用特殊样式
-        let rankClass = '';
-        if (index === 0) rankClass = 'rank-1';
-        else if (index === 1) rankClass = 'rank-2';
-        else if (index === 2) rankClass = 'rank-3';
-        
-        html += `
-          <tr class="${rankClass}">
-            <td>${score.classification === '0' ? '个人项目' : '团体项目'}</td>
-            <td>第${index + 1}名</td>
-            <td>${score.teamName || '-'}</td>
-            <td>${score.athleteCode || '-'}</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 += `
+      `).join('')}
     </body>
     </html>
   `;
-
-  return html;
 };
 
 /**
@@ -847,12 +972,16 @@ const calculateParticipantCounts = async () => {
       
       // 计算完赛人数(有成绩记录的)
       const completedScores = scores.filter(score => {
-        const individualScore = parseFloat(score.individualPerformance);
-        const teamScore = parseFloat(score.teamPerformance);
-        
         // 成绩必须存在且大于0
-        return (!isNaN(individualScore) && individualScore > 0) || 
-              (!isNaN(teamScore) && teamScore > 0);
+        const sc = score.classification === '0' ? score.individualPerformance : score.teamPerformance;
+        if (sc === null || sc === undefined || sc === '' || sc === '00:00:00.000') {
+          return false;
+        }
+        if (typeof  sc === 'number') {
+          return !isNaN(sc) && sc > 0;
+        }else if(typeof  sc === 'string'){
+          return sc !== '0';
+        }
       });
       console.log('completedScores: ', completedScores);
       (project as any).completedParticipants = completedScores.length;
@@ -907,3 +1036,6 @@ onMounted(() => {
   loadProjects();
 });
 </script>
+
+
+

+ 135 - 42
src/views/system/gameScore/print.vue

@@ -9,22 +9,22 @@
     <!-- 打印内容 -->
     <div class="print-content" ref="printContent">
       <div class="print-header">
-        <h1>赛事管理系统 - 成绩打印(前3名)</h1>
+        <h1>赛事管理系统 - 成绩打印(前{{ topCount }}名)</h1>
         <p>打印时间: {{ printTime }}</p>
       </div>
 
       <!-- 项目成绩表格 -->
       <div v-for="project in projectScores" :key="project.projectId" class="project-section">
         <div class="project-title">
-          <span class="title-label">竞赛序员</span> {{ project.projectId }} 
-          <span class="title-label">项目类型-项目名称</span> {{ project.projectTypeName }} {{ project.projectName }}
+          <span class="title-label">{{ project.projectId }} </span> 
+          <span class="title-label">{{ project.projectTypeName }}-{{ 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>
@@ -33,14 +33,13 @@
             </tr>
           </thead>
           <tbody>
-            <tr v-for="(score, index) in project.scores.slice(0, 3)" :key="score.scoreId" 
-                :class="index === 0 ? 'rank-1' : index === 1 ? 'rank-2' : 'rank-3'">
+            <tr v-for="(score, index) in project.scores.slice(0, topCount)" :key="score.scoreId" >
               <td>{{ score.classification === '0' ? '个人项目' : '团体项目' }}</td>
-              <td>第{{ index + 1 }}名</td>
+              <td>第{{ Number(index) + 1 }}名</td>
               <td>{{ score.teamName || '-' }}</td>
               <td>{{ score.athleteCode || '-' }}</td>
               <td>{{ score.athleteName || '-' }}</td>
-              <td>{{ formatScore(score.individualPerformance || score.teamPerformance) }}</td>
+              <td>{{ score.classification === '0' ? formatScore(score.individualPerformance) : formatScore(score.teamPerformance)}}</td>
               <td>{{ score.scorePoint || 0 }}</td>
             </tr>
           </tbody>
@@ -51,12 +50,13 @@
 </template>
 
 <script setup lang="ts" name="GameScorePrint">
-import { ref, onMounted, computed } from 'vue'
+import { ref, onMounted, computed, nextTick } from 'vue'
 import { useRoute, useRouter } from 'vue-router'
 import { getProjectScoreData } from '@/api/system/gameScore'
 import { getGameEventProject } from '@/api/system/gameEventProject'
 import { GameScoreVO } from '@/api/system/gameScore/types'
 import { GameEventProjectVO } from '@/api/system/gameEventProject/types'
+import { ElMessage } from 'element-plus'
 
 const { proxy } = getCurrentInstance() as ComponentInternalInstance;
 const { game_project_type } = toRefs<any>(proxy?.useDict('game_project_type'));
@@ -69,6 +69,7 @@ const isPrinting = ref(false)
 const printContent = ref<HTMLElement>()
 const projectScores = ref<any[]>([])
 const loading = ref(false)
+const topCount = ref(3) // 默认值为3
 
 // 计算属性
 const printTime = computed(() => {
@@ -86,8 +87,18 @@ const loadProjectScores = async () => {
   try {
     loading.value = true
     
-    // 从路由参数获取项目ID
+    // 从路由参数获取项目ID和topCount
     const projectId = route.params.projectId as string
+    const topCountParam = route.params.topCount as string
+    
+    // 如果有topCount参数,则使用它,否则保持默认值
+    if (topCountParam) {
+      const count = parseInt(topCountParam)
+      if (count > 0) {
+        topCount.value = count
+      }
+    }
+    
     if (!projectId) {
       ElMessage.error('项目ID不能为空')
       return
@@ -105,7 +116,6 @@ const loadProjectScores = async () => {
       pageNum: 1,
       pageSize: 1000 // 获取所有成绩
     })
-
     // 处理数据格式
     const scores = scoreRes.rows || []
     const sortedScores = scores.sort((a: GameScoreVO, b: GameScoreVO) => {
@@ -143,29 +153,6 @@ const getProjectTypeName = (type: string) => {
   return typeItem ? typeItem.label : '未知';
 }
 
-// 获取分组类型名称
-// const getGroupTypeName = (type: string) => {
-//   const groupMap: Record<string, string> = {
-//     '1': '甲组',
-//     '2': '乙组',
-//     '3': '丙组',
-//     '4': '丁组'
-//   }
-//   return groupMap[type] || '未知组'
-// }
-
-// 获取队伍名称(这里需要根据实际API调整)
-// const getTeamName = (teamId: string | number) => {
-//   // 实际项目中应该调用队伍API获取名称
-//   return `队伍${teamId}`
-// }
-
-// // 获取运动员姓名(这里需要根据实际API调整)
-// const getAthleteName = (athleteId: string | number) => {
-//   // 实际项目中应该调用运动员API获取姓名
-//   return `运动员${athleteId}`
-// }
-
 // 打印页面
 const printPage = () => {
   isPrinting.value = true
@@ -233,7 +220,7 @@ onMounted(() => {
 }
 
 .title-label {
-  color: #f56c6c;
+  /* color: #f56c6c; */
   font-weight: bold;
 }
 
@@ -260,27 +247,133 @@ onMounted(() => {
   color: #333;
 }
 
-.rank-1 { background-color: #fff7e6; font-weight: bold; }
+.rank-1 { background-color: #fff7e6; }
 .rank-2 { background-color: #f6ffed; }
 .rank-3 { background-color: #f0f9ff; }
 
 /* 打印样式 */
 @media print {
+  * {
+    -webkit-print-color-adjust: exact !important;
+    print-color-adjust: exact !important;
+    background: transparent !important;
+    box-shadow: none !important;
+    text-shadow: none !important;
+  }
+  
+  body {
+    font-family: SimSun, "Times New Roman", serif !important;
+    font-size: 12pt !important;
+    line-height: 1.4 !important;
+    color: #000 !important;
+  }
+  
   .print-actions {
-    display: none;
+    display: none !important;
   }
   
   .print-container {
-    padding: 0;
+    padding: 0 !important;
+    max-width: 100% !important;
+  }
+  
+  .print-content {
+    width: 100% !important;
+    max-width: 100% !important;
   }
   
   .project-section {
-    page-break-inside: avoid;
+    page-break-inside: avoid !important;
+    page-break-after: auto !important;
+  }
+  
+  .score-table {
+    width: 100% !important;
+    border-collapse: collapse !important;
+    font-size: 11pt !important;
+  }
+  
+  .score-table th,
+  .score-table td {
+    border: 1px solid #000 !important;
+    padding: 5pt !important;
+    text-align: center !important;
+    vertical-align: middle !important;
   }
   
   .score-table th {
-    background: #f8f9fa !important;
-    -webkit-print-color-adjust: exact;
+    background-color: #f8f9fa !important;
+    color: #000 !important;
+    font-weight: bold !important;
+  }
+  
+  /* 确保排名样式在打印中正确显示 */
+  .rank-1 {
+    background-color: #fff7e6 !important;
+    color: #000 !important;
+  }
+  
+  .rank-2 {
+    background-color: #f6ffed !important;
+    color: #000 !important;
+  }
+  
+  .rank-3 {
+    background-color: #f0f9ff !important;
+    color: #000 !important;
+  }
+  
+  /* 设置页面边距 */
+  @page {
+    margin: 20mm !important;
+    size: A4 !important;
+  }
+  
+  /* 避免第一页顶部和最后一页底部有太多空白 */
+  .print-header {
+    page-break-after: avoid !important;
+  }
+  
+  /* 确保表格不被截断 */
+  .score-table {
+    page-break-inside: avoid !important;
+  }
+  
+  .score-table thead {
+    display: table-header-group !important; /* 确保表头在每页重复 */
+  }
+  
+  .score-table tbody {
+    display: table-row-group !important;
+  }
+  
+  /* 隐藏可能干扰打印的元素 */
+  .no-print {
+    display: none !important;
+  }
+  
+  /* 确保字体大小在打印中保持一致 */
+  h1 {
+    font-size: 18pt !important;
+    margin-bottom: 10pt !important;
+    color: #000 !important;
+  }
+  
+  .project-title {
+    font-size: 14pt !important;
+    margin-bottom: 10pt !important;
+    padding: 8pt !important;
+    border-left: 4px solid #000 !important;
+    background-color: #f5f5f5 !important;
+    color: #000 !important;
+  }
+  
+  /* 确保在IE浏览器中也能正常打印 */
+  @media print and (-ms-high-contrast: none), print and (-ms-high-contrast: active) {
+    * {
+      color-adjust: exact !important;
+    }
   }
 }
-</style> 
+</style> 
+