Browse Source

feat(game-event): 添加澳亚特设备成绩上传功能

- 新增 AvtScoreItem 实体类用于存储径赛成绩数据
- 新增 AvtScoreUploadVo 视图对象处理成绩上传请求
- 在 ElectrometerController 中添加/uploadAvtScore/timer 接口- 实现 uploadAvtScore 方法解析并保存澳亚特设备成绩数据
-为多个 VO 类添加 Jackson 注解以支持特定字段映射- 修改 GameTeam 相关类中的 athleteNum 类型从 Long 改为 Integer- 优化成绩导出逻辑与分页查询边界条件
- 调整物理设备成绩上传接口参数名称以匹配实际请求
- 完善队伍信息查询时关联分组名称的 SQL 语句- 修复运动员编号和队伍编号重复校验时缺少 eventId 条件的问题
zhou 1 month ago
parent
commit
2f8d33f8dc
23 changed files with 440 additions and 67 deletions
  1. 4 4
      pom.xml
  2. 32 11
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/app/ElectrometerController.java
  3. 3 3
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/app/PhysicalController.java
  4. 1 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/GameTeam.java
  5. 59 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/app/AvtScoreItem.java
  6. 1 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/bo/GameAthleteBo.java
  7. 1 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/bo/GameTeamBo.java
  8. 1 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GameTeamVo.java
  9. 39 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/app/AvtScoreUploadVo.java
  10. 4 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/app/DistanceScoreUploadVo.java
  11. 7 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/app/ElectrometerDataItemVo.java
  12. 4 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/app/ElectrometerScoreUploadVo.java
  13. 8 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/app/PhysicalTestVo.java
  14. 3 1
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameAthleteCompetitionGroupMapper.java
  15. 2 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameScoreMapper.java
  16. 7 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameTeamMapper.java
  17. 10 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/app/IElectrometerService.java
  18. 1 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameAthleteServiceImpl.java
  19. 38 38
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameScoreServiceImpl.java
  20. 4 3
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameTeamServiceImpl.java
  21. 2 2
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/IEnrollServiceImpl.java
  22. 175 0
      ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/app/ElectrometerServiceImpl.java
  23. 34 0
      ruoyi-modules/ruoyi-game-event/src/main/resources/mapper/system/GameTeamMapper.xml

+ 4 - 4
pom.xml

@@ -80,10 +80,6 @@
                 <monitor.username>ruoyi</monitor.username>
                 <monitor.password>123456</monitor.password>
             </properties>
-            <activation>
-                <!-- 默认环境 -->
-                <activeByDefault>true</activeByDefault>
-            </activation>
 
         </profile>
         <profile>
@@ -105,6 +101,10 @@
                 <monitor.username>ruoyi</monitor.username>
                 <monitor.password>123456</monitor.password>
             </properties>
+            <activation>
+                <!-- 默认环境 -->
+                <activeByDefault>true</activeByDefault>
+            </activation>
 
         </profile>
     </profiles>

+ 32 - 11
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/app/ElectrometerController.java

@@ -3,6 +3,7 @@ package org.dromara.system.controller.app;
 import cn.dev33.satoken.annotation.SaIgnore;
 import lombok.RequiredArgsConstructor;
 import org.dromara.common.core.domain.R;
+import org.dromara.system.domain.vo.app.AvtScoreUploadVo;
 import org.dromara.system.domain.vo.app.DistanceScoreUploadVo;
 import org.dromara.system.domain.vo.app.ElectrometerDataItemVo;
 import org.dromara.system.domain.vo.app.ElectrometerScoreUploadVo;
@@ -53,17 +54,17 @@ public class ElectrometerController {
      * @param eventId 赛事ID (通过请求头 X-Dbname 传递)
      * @return R<String> 上传结果
      */
-    @PostMapping("/aytuploadscore/timer")
-    public R<String> uploadScore(
-        @RequestBody List<ElectrometerScoreUploadVo> scoreUpload,
-        @RequestHeader(value = "X-Dbname") Long eventId) {
-        try {
-            String result = electrometerService.uploadScore(eventId, scoreUpload);
-            return R.ok(result);
-        } catch (Exception e) {
-            return R.fail("计时类项目成绩上传失败:" + e.getMessage());
-        }
-    }
+//    @PostMapping("/aytuploadscore/timer")
+//    public R<String> uploadScore(
+//        @RequestBody List<ElectrometerScoreUploadVo> scoreUpload,
+//        @RequestHeader(value = "X-Dbname") Long eventId) {
+//        try {
+//            String result = electrometerService.uploadScore(eventId, scoreUpload);
+//            return R.ok(result);
+//        } catch (Exception e) {
+//            return R.fail("计时类项目成绩上传失败:" + e.getMessage());
+//        }
+//    }
 
     /**
      * 远度距离类项目成绩上传
@@ -83,4 +84,24 @@ public class ElectrometerController {
             return R.fail("远度距离类项目成绩上传失败:" + e.getMessage());
         }
     }
+
+    /**
+     * 径赛成绩上传(电计设备)- 新格式
+     * 对应图片中的接口格式:POST /api/electrometer/avtuploadscore
+     *
+     * @param scoreUpload 成绩上传数据,包含cc_dm、zc、cj字段
+     * @param eventId 赛事ID (通过请求头 X-Dbname 传递)
+     * @return R<String> 上传结果
+     */
+    @PostMapping("/avtuploadscore/timer")
+    public R<String> uploadAvtScore(
+        @RequestBody AvtScoreUploadVo scoreUpload,
+        @RequestHeader(value = "X-Dbname") String eventId) {
+        try {
+            String result = electrometerService.uploadAvtScore(eventId, scoreUpload);
+            return R.ok(result);
+        } catch (Exception e) {
+            return R.fail("径赛成绩上传失败:" + e.getMessage());
+        }
+    }
 }

+ 3 - 3
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/app/PhysicalController.java

@@ -69,9 +69,9 @@ public class PhysicalController {
      */
     @PostMapping("/SendResults")
     public ResponseEntity<Map<String, Object>> handleSendResults(
-        @RequestParam String testName,
-        @RequestParam int recordCount,
-        @RequestParam String resultInfo) {
+        @RequestParam("TestName") String testName,
+        @RequestParam("RecordCount") int recordCount,
+        @RequestParam("ResultInfo") String resultInfo) {
         try {
             // 2. 调用解析方法,根据 TestName 不同采用不同解析策略
             PhysicalDeviceVo deviceVo = parseAndSaveResults(testName, recordCount, resultInfo);

+ 1 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/GameTeam.java

@@ -65,7 +65,7 @@ public class GameTeam extends TenantEntity {
     /**
      * 人数
      */
-    private Long athleteNum;
+    private Integer athleteNum;
 
     /**
      * 号码段

+ 59 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/app/AvtScoreItem.java

@@ -0,0 +1,59 @@
+package org.dromara.system.domain.app;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class AvtScoreItem  implements Serializable {
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 场次代码(分组ID)
+     */
+    private Long ccdm;
+
+    /**
+     * 运动员编号
+     */
+    private String athleteCode;
+
+    /**
+     * 名次
+     */
+    private Integer rank;
+
+    /**
+     * 成绩(以分钟为单位)
+     */
+    private String score;
+
+    /**
+     * 风速
+     */
+    private String windSpeed;
+
+    /**
+     * 反应时
+     */
+    private String reactionTime;
+
+    /**
+     * 状态
+     */
+    private String status;
+
+    /**
+     * 组次
+     */
+    private Long groupIndex;
+
+    /**
+     * 道次
+     */
+    private Long trackIndex;
+
+}

+ 1 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/bo/GameAthleteBo.java

@@ -19,7 +19,7 @@ import java.util.List;
  */
 @Data
 @EqualsAndHashCode(callSuper = true)
-@AutoMapper(target = GameAthlete.class, reverseConvertGenerate = false)
+@AutoMapper(target = GameAthlete.class)
 public class GameAthleteBo extends BaseEntity {
 
     /**

+ 1 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/bo/GameTeamBo.java

@@ -78,7 +78,7 @@ public class GameTeamBo extends BaseEntity {
      * 人数
      */
 //    @NotNull(message = "人数不能为空", groups = { AddGroup.class, EditGroup.class })
-    private Long athleteNum;
+    private Integer athleteNum;
 
     /**
      * 号码段

+ 1 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GameTeamVo.java

@@ -89,7 +89,7 @@ public class GameTeamVo implements Serializable {
      * 人数
      */
     @ExcelProperty(value = "人数")
-    private Long athleteNum;
+    private Integer athleteNum;
 
     /**
      * 号码段

+ 39 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/app/AvtScoreUploadVo.java

@@ -0,0 +1,39 @@
+package org.dromara.system.domain.vo.app;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 澳亚特设备成绩上传请求视图对象(新格式)
+ * 对应图片中的JSON格式:{cc_dm:"464",zc:"1",cj:"464,0302,1,12.313,,,,1,4|464,0219,2,21.313,,,,1,1|..."}
+ *
+ * @author zlt
+ * @date 2025-01-27
+ */
+@Data
+public class AvtScoreUploadVo implements Serializable {
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 场次代码(分组ID)
+     */
+    @JsonProperty("cc_dm")
+    private String ccDm;
+
+    /**
+     * 组次
+     */
+    @JsonProperty("zc")
+    private String zc;
+
+    /**
+     * 成绩数据
+     * 格式:场次代码,编号,名次,成绩,风速,反应时,状态,组次,道次|场次代码,编号,名次,成绩,风速,反应时,状态,组次,道次......
+     */
+    @JsonProperty("cj")
+    private String cj;
+}

+ 4 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/app/DistanceScoreUploadVo.java

@@ -1,5 +1,6 @@
 package org.dromara.system.domain.vo.app;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
 
 import java.math.BigDecimal;
@@ -16,16 +17,19 @@ public class DistanceScoreUploadVo {
     /**
      * 场次代码(分组ID)
      */
+    @JsonProperty("cc_dm")
     private Long ccdm;
 
     /**
      * 组次
      */
+    @JsonProperty("zc")
     private Long groupIndex;
 
     /**
      * 成绩数据(格式:序号,后三轮序号,号码,姓名,成绩1,风速1,成绩2,风速2,成绩3,风速3,成绩4,风速4,成绩5,风速5,成绩6,风速6,名次|......)
      */
+    @JsonProperty("cj")
     private String cj;
 
     @Data

+ 7 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/app/ElectrometerDataItemVo.java

@@ -1,5 +1,6 @@
 package org.dromara.system.domain.vo.app;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
 import java.io.Serializable;
 import java.util.Date;
@@ -17,6 +18,7 @@ public class ElectrometerDataItemVo implements Serializable {
     /**
      * 项目类型(计算规则), 对应 game_event_project.score_rule
      */
+    @JsonProperty("tjs_dm")
     private String tjsDm;
 
     /**
@@ -47,21 +49,25 @@ public class ElectrometerDataItemVo implements Serializable {
     /**
      * 组别名称, 甲组, 对应分组名称
      */
+    @JsonProperty("zb_mc")
     private String zbMc;
 
     /**
      * 项目名称, 对应 game_event_project.project_name
      */
+    @JsonProperty("xm_mc")
     private String xmMc;
 
     /**
      * 赛次名称(预赛, 复赛, 半决赛, 决赛), 对应比赛轮次
      */
+    @JsonProperty("sc_mc")
     private String scMc;
 
     /**
      * 场次代码, 编排给的比赛分组唯一标识, 对应 game_athlete_competition_group.group_id
      */
+    @JsonProperty("cc_dm")
     private String ccDm;
 
     /**
@@ -82,5 +88,6 @@ public class ElectrometerDataItemVo implements Serializable {
     /**
      * 比赛单元, 对应比赛单元
      */
+    @JsonProperty("bs_dm")
     private String bsDm;
 }

+ 4 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/app/ElectrometerScoreUploadVo.java

@@ -1,6 +1,9 @@
 package org.dromara.system.domain.vo.app;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
+
+import java.io.Serial;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.List;
@@ -13,6 +16,7 @@ import java.util.List;
  */
 @Data
 public class ElectrometerScoreUploadVo implements Serializable {
+    @Serial
     private static final long serialVersionUID = 1L;
 
     /**

+ 8 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/app/PhysicalTestVo.java

@@ -1,24 +1,31 @@
 package org.dromara.system.domain.vo.app;
 
+import com.fasterxml.jackson.annotation.JsonProperty;
 import lombok.Data;
 
 import java.math.BigDecimal;
-import java.util.Date;
 
 @Data
 public class PhysicalTestVo {
     //项目名称
+    @JsonProperty("testname")
     private String testName;
     //项目key
+    @JsonProperty("testkey")
     private String testKey;
     //对应学生身份证号
+    @JsonProperty("user_id")
     private String userId;
     //学生姓名
+    @JsonProperty("name")
     private String name;
     //测试时间
+    @JsonProperty("timestamp")
     private String testTime;
     //测试结果
+    @JsonProperty("result_data")
     private String resultData;
     //测试分数
+    @JsonProperty("result_score")
     private BigDecimal resultScore;
 }

+ 3 - 1
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameAthleteCompetitionGroupMapper.java

@@ -1,5 +1,6 @@
 package org.dromara.system.mapper;
 
+import org.apache.ibatis.annotations.Mapper;
 import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
 import org.dromara.system.domain.GameAthleteCompetitionGroup;
 import org.dromara.system.domain.vo.GameAthleteCompetitionGroupVo;
@@ -10,6 +11,7 @@ import org.dromara.system.domain.vo.GameAthleteCompetitionGroupVo;
  * @author zlt
  * @date 2025-08-28
  */
+@Mapper
 public interface GameAthleteCompetitionGroupMapper extends BaseMapperPlus<GameAthleteCompetitionGroup, GameAthleteCompetitionGroupVo> {
 
-} 
+}

+ 2 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameScoreMapper.java

@@ -1,5 +1,6 @@
 package org.dromara.system.mapper;
 
+import org.apache.ibatis.annotations.Mapper;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
 import org.dromara.system.domain.GameScore;
@@ -16,6 +17,7 @@ import java.util.Map;
  * @author zlt
  * @date 2025-07-30
  */
+@Mapper
 public interface GameScoreMapper extends BaseMapperPlus<GameScore, GameScoreVo> {
 
     /**

+ 7 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/mapper/GameTeamMapper.java

@@ -48,4 +48,11 @@ public interface GameTeamMapper extends BaseMapperPlus<GameTeam, GameTeamVo> {
         "</foreach>" +")"+
         "</script>")
     List<GameTeamBo> findByAthleteIds(Collection<Long> athleteIds);
+
+    /**
+     * 查询队伍列表并包含分组名
+     * @param bo 查询条件
+     * @return 队伍列表
+     */
+    List<GameTeamVo> selectVoListWithGroupName(GameTeamBo bo);
 }

+ 10 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/app/IElectrometerService.java

@@ -1,5 +1,6 @@
 package org.dromara.system.service.app;
 
+import org.dromara.system.domain.vo.app.AvtScoreUploadVo;
 import org.dromara.system.domain.vo.app.DistanceScoreUploadVo;
 import org.dromara.system.domain.vo.app.ElectrometerDataItemVo;
 import org.dromara.system.domain.vo.app.ElectrometerScoreUploadVo;
@@ -40,4 +41,13 @@ public interface IElectrometerService {
      * @return 上传结果
      */
     String uploadDistanceScore(Long eventId, DistanceScoreUploadVo scoreUpload);
+
+    /**
+     * 上传径赛成绩(电计设备)- 新格式
+     *
+     * @param eventId 赛事ID
+     * @param scoreUpload 成绩上传数据,包含cc_dm、zc、cj字段
+     * @return 上传结果
+     */
+    String uploadAvtScore(String eventId, AvtScoreUploadVo scoreUpload);
 }

+ 1 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameAthleteServiceImpl.java

@@ -496,6 +496,7 @@ public class GameAthleteServiceImpl implements IGameAthleteService {
         //校验运动员编号是否存在重复值
         if (entity.getAthleteCode() != null){
             List<GameAthlete> list = baseMapper.selectList(new LambdaQueryWrapper<GameAthlete>()
+                .eq(GameAthlete::getEventId, entity.getEventId())
                 .eq(GameAthlete::getAthleteCode, entity.getAthleteCode())
                 .ne( entity.getAthleteId() != null, GameAthlete::getAthleteId, entity.getAthleteId())
             );

+ 38 - 38
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameScoreServiceImpl.java

@@ -308,7 +308,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
 
         // 获取当前页的数据
         List<Map<String, Object>> pageData = new ArrayList<>();
-        if (startIndex < total) {
+        if (startIndex <= total) {
             pageData = allDataList.subList(startIndex, endIndex);
             log.info("当前页数据量: {}", pageData.size());
         } else {
@@ -1503,33 +1503,33 @@ public class GameScoreServiceImpl implements IGameScoreService {
     public void exportScoresDetail(Long eventId, HttpServletResponse response) {
         try {
             log.info("开始导出成绩详情,eventId: {}", eventId);
-            
+
             // 1. 获取所有项目
             List<GameEventProjectVo> projects = gameEventProjectService.queryListByEventId(eventId);
             if (projects.isEmpty()) {
                 throw new RuntimeException("未找到赛事项目");
             }
-            
+
             // 2. 创建Excel工作簿
             try (Workbook workbook = new XSSFWorkbook()) {
-                
+
                 // 3. 创建样式
                 CellStyle headerStyle = createHeaderStyle(workbook);
                 CellStyle dataStyleOdd = createDataStyle(workbook, IndexedColors.WHITE);
                 CellStyle dataStyleEven = createDataStyle(workbook, IndexedColors.GREY_25_PERCENT);
-                
+
                 // 4. 为每个项目创建Sheet页
                 for (GameEventProjectVo project : projects) {
                     createProjectSheet(workbook, project, eventId, headerStyle, dataStyleOdd, dataStyleEven);
                 }
-                
+
                 // 5. 设置响应头并输出
                 setResponseHeaders(response, "成绩详情表");
                 workbook.write(response.getOutputStream());
             }
-            
+
             log.info("成绩详情导出完成");
-            
+
         } catch (Exception e) {
             log.error("导出成绩详情失败", e);
             throw new RuntimeException("导出失败:" + e.getMessage());
@@ -1539,7 +1539,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
     /**
      * 为单个项目创建Sheet页
      */
-    private void createProjectSheet(Workbook workbook, GameEventProjectVo project, Long eventId, 
+    private void createProjectSheet(Workbook workbook, GameEventProjectVo project, Long eventId,
         CellStyle headerStyle, CellStyle dataStyleOdd, CellStyle dataStyleEven) {
 
         // 1. 创建Sheet页,名称限制在31个字符内
@@ -1548,8 +1548,8 @@ public class GameScoreServiceImpl implements IGameScoreService {
 
         // 2. 获取项目详细数据
         List<Map<String, Object>> projectData = getProjectScoreDataAll(
-            eventId, 
-            project.getProjectId(), 
+            eventId,
+            project.getProjectId(),
             project.getClassification()
         );
 
@@ -1568,7 +1568,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
      */
     private List<Map<String, Object>> getProjectScoreDataAll(Long eventId, Long projectId, String classification) {
         log.info("获取项目全部数据: eventId={}, projectId={}, classification={}", eventId, projectId, classification);
-        
+
         if ("0".equals(classification)) {
             // 个人项目:获取所有运动员数据
             return getIndividualProjectDataAll(eventId, projectId);
@@ -1583,13 +1583,13 @@ public class GameScoreServiceImpl implements IGameScoreService {
      */
     private List<Map<String, Object>> getIndividualProjectDataAll(Long eventId, Long projectId) {
         List<Map<String, Object>> resultList = new ArrayList<>();
-        
+
         // 查询参与该项目的所有运动员(不分页)
         List<GameAthleteVo> athletes = gameAthleteService.queryListByEventIdAndProjectId(eventId, projectId, null);
-        
+
         for (GameAthleteVo athlete : athletes) {
             Map<String, Object> data = new HashMap<>();
-            
+
             // 基础信息
             data.put("athleteId", athlete.getAthleteId());
             data.put("userId", athlete.getUserId());
@@ -1600,7 +1600,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
             data.put("name", athlete.getName());
             data.put("unit", athlete.getUnit());
             data.put("groupType", athlete.getGroupType());
-            
+
             // 队伍信息
             if (athlete.getTeamId() != null) {
                 GameTeamVo team = gameTeamService.queryById(athlete.getTeamId());
@@ -1609,7 +1609,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
                     data.put("teamCode", team.getTeamCode());
                 }
             }
-            
+
             // 成绩信息
             GameScoreVo score = getScoreByAthleteIdAndProjectId(athlete.getAthleteId(), projectId);
             if (score != null) {
@@ -1628,10 +1628,10 @@ public class GameScoreServiceImpl implements IGameScoreService {
                 data.put("scoreRank", 0);
                 data.put("updateTime", "");
             }
-            
+
             resultList.add(data);
         }
-        
+
         return resultList;
     }
 
@@ -1641,30 +1641,30 @@ public class GameScoreServiceImpl implements IGameScoreService {
     private List<Map<String, Object>> getTeamProjectDataAll(Long eventId, Long projectId) {
         List<Map<String, Object>> resultList = new ArrayList<>();
         Set<Long> processedTeamIds = new HashSet<>();
-        
+
         // 查询参与该项目的所有运动员
         List<GameAthleteVo> athletes = gameAthleteService.queryListByEventIdAndProjectId(eventId, projectId, null);
-        
+
         for (GameAthleteVo athlete : athletes) {
             if (athlete.getTeamId() == null || processedTeamIds.contains(athlete.getTeamId())) {
                 continue;
             }
-            
+
             processedTeamIds.add(athlete.getTeamId());
-            
+
             // 查询队伍信息
             GameTeamVo team = gameTeamService.queryById(athlete.getTeamId());
             if (team == null) {
                 continue;
             }
-            
+
             Map<String, Object> data = new HashMap<>();
             data.put("teamId", team.getTeamId());
             data.put("teamName", team.getTeamName());
             data.put("teamCode", team.getTeamCode());
             data.put("eventId", eventId);
             data.put("projectId", projectId);
-            
+
             // 查询成绩信息
             GameScoreVo score = getScoreByAthleteIdAndProjectId(athlete.getAthleteId(), projectId);
             if (score != null) {
@@ -1682,10 +1682,10 @@ public class GameScoreServiceImpl implements IGameScoreService {
                 data.put("scoreRank", 0);
                 data.put("updateTime", "");
             }
-            
+
             resultList.add(data);
         }
-        
+
         return resultList;
     }
 
@@ -1695,15 +1695,15 @@ public class GameScoreServiceImpl implements IGameScoreService {
     private void createProjectHeaderRow(Sheet sheet, GameEventProjectVo project, CellStyle headerStyle) {
         Row headerRow = sheet.createRow(0);
         int colIndex = 0;
-        
+
         // 根据项目类型确定列标题
         if ("0".equals(project.getClassification())) {
             // 个人项目列标题
             String[] headers = {
-                "序号", "队伍编号", "队伍名称", "姓名", "号码", 
+                "序号", "队伍编号", "队伍名称", "姓名", "号码",
                 "个人成绩", "积分", "排名", "更新时间"
             };
-            
+
             for (String header : headers) {
                 Cell cell = headerRow.createCell(colIndex++);
                 cell.setCellValue(header);
@@ -1712,10 +1712,10 @@ public class GameScoreServiceImpl implements IGameScoreService {
         } else {
             // 团体项目列标题
             String[] headers = {
-                "序号", "队伍编号", "队伍名称", "团队成绩", 
+                "序号", "队伍编号", "队伍名称", "团队成绩",
                 "积分", "排名", "更新时间"
             };
-            
+
             for (String header : headers) {
                 Cell cell = headerRow.createCell(colIndex++);
                 cell.setCellValue(header);
@@ -1727,7 +1727,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
     /**
      * 填充项目数据行
      */
-    private void fillProjectDataRows(Sheet sheet, List<Map<String, Object>> projectData, 
+    private void fillProjectDataRows(Sheet sheet, List<Map<String, Object>> projectData,
     GameEventProjectVo project, CellStyle dataStyleOdd, CellStyle dataStyleEven) {
 
         int rowIndex = 1;
@@ -1771,7 +1771,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
         if (projectName == null) {
             return "项目";
         }
-        
+
         // 替换Excel不允许的特殊字符
         String cleanName = projectName
             .replace("*", "×")     // 星号替换为乘号
@@ -1782,22 +1782,22 @@ public class GameScoreServiceImpl implements IGameScoreService {
             .replace("]", ")")     // 右方括号替换为右括号
             .replace(":", ":")    // 英文冒号替换为中文冒号
             .trim();               // 去除首尾空格
-        
+
         // 处理单引号问题
         if (cleanName.startsWith("'") || cleanName.endsWith("'")) {
             cleanName = cleanName.replace("'", "_");
         }
-        
+
         // 如果处理后为空,使用默认名称
         if (cleanName.isEmpty()) {
             cleanName = "项目";
         }
-        
+
         // 限制长度在31个字符内
         if (cleanName.length() > 31) {
             cleanName = cleanName.substring(0, 31);
         }
-        
+
         return cleanName;
     }
 

+ 4 - 3
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameTeamServiceImpl.java

@@ -154,8 +154,8 @@ public class GameTeamServiceImpl implements IGameTeamService {
                 bo.setEventId((Long) cacheObject);
             }
         }
-        LambdaQueryWrapper<GameTeam> lqw = buildQueryWrapper(bo);
-        List<GameTeamVo> list = baseMapper.selectVoList(lqw);
+        // 使用包含分组名的查询方法
+        List<GameTeamVo> list = baseMapper.selectVoListWithGroupName(bo);
         list.forEach(vo -> {
             if (vo.getAthleteValue() != null) {
                 vo.setAthleteList(JSONUtil.toList(vo.getAthleteValue(), Long.class));
@@ -270,6 +270,7 @@ public class GameTeamServiceImpl implements IGameTeamService {
         if (entity.getTeamCode() != null){
             Long count = baseMapper.selectCount(
                 Wrappers.lambdaQuery(GameTeam.class)
+                    .eq(GameTeam::getEventId, entity.getEventId())
                     .eq(GameTeam::getTeamCode, entity.getTeamCode())
                     .ne(entity.getTeamId() != null,GameTeam::getTeamId, entity.getTeamId())
             );
@@ -386,7 +387,7 @@ public class GameTeamServiceImpl implements IGameTeamService {
         // 将运动员ID列表转换为JSON字符串
         String athleteValue = JSONUtil.toJsonStr(athleteIds);
         team.setAthleteValue(athleteValue);
-        team.setAthleteNum((long) athleteIds.size());
+        team.setAthleteNum(athleteIds.size());
 
         // 更新队伍信息
         return baseMapper.updateById(team) > 0;

+ 2 - 2
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/IEnrollServiceImpl.java

@@ -225,7 +225,7 @@ public class IEnrollServiceImpl implements IEnrollService {
             gameTeamBo.setTeamName(teamName);
             gameTeamBo.setLeader(name);
             gameTeamBo.setAthleteValue(JSONUtil.toJsonStr(Arrays.asList(athleteId)));
-            gameTeamBo.setAthleteNum(1L);
+            gameTeamBo.setAthleteNum(1);
             gameTeamBo.setNumberRange(startNumber + "-" + endNumber);
             gameTeamBo.setCreateDept(-1L);
             gameTeamBo.setCreateBy(-1L);
@@ -595,7 +595,7 @@ public class IEnrollServiceImpl implements IEnrollService {
                 gameTeamBo.setTeamName(teamName);
                 gameTeamBo.setLeader(athletes.get(0).getLeader());
                 gameTeamBo.setAthleteValue(JSONUtil.toJsonStr(athletesId));
-                gameTeamBo.setAthleteNum(Long.valueOf(athletes.size()));
+                gameTeamBo.setAthleteNum(athletes.size());
                 gameTeamBo.setNumberRange(numberRange); // 设置300个号码段
                 gameTeamBo.setStatus("0");
                 gameTeamService.insertByBo(gameTeamBo);

+ 175 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/app/ElectrometerServiceImpl.java

@@ -3,6 +3,8 @@ package org.dromara.system.service.impl.app;
 import com.esotericsoftware.minlog.Log;
 import lombok.RequiredArgsConstructor;
 import org.dromara.system.domain.*;
+import org.dromara.system.domain.app.AvtScoreItem;
+import org.dromara.system.domain.vo.app.AvtScoreUploadVo;
 import org.dromara.system.domain.vo.app.DistanceScoreUploadVo;
 import org.dromara.system.domain.vo.app.ElectrometerDataItemVo;
 import org.dromara.system.domain.vo.app.ElectrometerScoreUploadVo;
@@ -406,4 +408,177 @@ public class ElectrometerServiceImpl implements IElectrometerService {
             return 0;
         }
     }
+
+    /**
+     * 上传径赛成绩(电计设备)- 新格式
+     *
+     * @param eventId 赛事ID
+     * @param scoreUpload 成绩上传数据,包含cc_dm、zc、cj字段
+     * @return 上传结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public String uploadAvtScore(String eventId, AvtScoreUploadVo scoreUpload) {
+        try {
+            Log.info("开始上传径赛成绩,赛事ID: {}", eventId);
+
+            // 解析cj字段中的数据
+            List<AvtScoreItem> scoreItems = parseAvtScoreData(scoreUpload.getCj());
+            if (scoreItems.isEmpty()) {
+                return "没有有效的成绩数据";
+            }
+
+            // 根据场次代码获取分组信息
+            Long groupId = Long.valueOf(scoreUpload.getCcDm());
+            GameAthleteCompetitionGroup groupInfo = gameAthleteCompetitionGroupMapper.selectById(groupId);
+            if (groupInfo == null) {
+                return "未找到对应的比赛分组信息";
+            }
+
+            // 获取项目信息
+            GameEventProject project = gameEventProjectMapper.selectById(groupInfo.getProjectId());
+            if (project == null) {
+                return "未找到对应的项目信息";
+            }
+
+            // 保存成绩数据
+            int successCount = 0;
+            for (AvtScoreItem scoreItem : scoreItems) {
+                if (saveAvtScoreRecord(Long.valueOf(eventId), project, scoreItem)) {
+                    successCount++;
+                }
+            }
+
+            Log.info("径赛成绩上传完成,成功保存 {} 条记录", String.valueOf(successCount));
+            return String.format("成绩上传成功,共保存 %d 条记录", successCount);
+
+        } catch (Exception e) {
+            Log.error("径赛成绩上传失败", e);
+            throw new RuntimeException("径赛成绩上传失败: " + e.getMessage());
+        }
+    }
+
+    /**
+     * 解析AVT成绩数据字符串
+     * 格式:场次代码,编号,名次,成绩,风速,反应时,状态,组次,道次|场次代码,编号,名次,成绩,风速,反应时,状态,组次,道次......
+     */
+    private List<AvtScoreItem> parseAvtScoreData(String scoreData) {
+        List<AvtScoreItem> scoreList = new ArrayList<>();
+
+        if (scoreData == null || scoreData.trim().isEmpty()) {
+            return scoreList;
+        }
+
+        String[] items = scoreData.split("\\|");
+        for (String item : items) {
+            if (item.trim().isEmpty()) {
+                continue;
+            }
+
+            String[] fields = item.split(",");
+            if (fields.length >= 9) {
+                try {
+                    AvtScoreItem scoreItem = new AvtScoreItem();
+                    scoreItem.setCcdm(Long.valueOf(fields[0])); // 场次代码
+                    scoreItem.setAthleteCode(fields[1]); // 编号
+                    scoreItem.setRank(fields[2].isEmpty() ? null : Integer.valueOf(fields[2])); // 名次
+                    scoreItem.setScore(fields[3].isEmpty() ? null : fields[3]); // 成绩
+                    scoreItem.setWindSpeed(fields[4].isEmpty() ? null : fields[4]); // 风速
+                    scoreItem.setReactionTime(fields[5].isEmpty() ? null : fields[5]); // 反应时
+                    scoreItem.setStatus(fields[6].isEmpty() ? null : fields[6]); // 状态
+                    scoreItem.setGroupIndex(fields[7].isEmpty() ? null : Long.valueOf(fields[7])); // 组次
+                    scoreItem.setTrackIndex(fields[8].isEmpty() ? null : Long.valueOf(fields[8])); // 道次
+
+                    scoreList.add(scoreItem);
+                } catch (Exception e) {
+                    Log.warn("解析AVT成绩数据失败: {}", item, e);
+                }
+            }
+        }
+
+        return scoreList;
+    }
+
+    /**
+     * 保存AVT成绩记录
+     */
+    private boolean saveAvtScoreRecord(Long eventId, GameEventProject project, AvtScoreItem scoreItem) {
+        try {
+            // 根据运动员编号查找运动员ID
+            LambdaQueryWrapper<GameAthlete> athleteWrapper = Wrappers.lambdaQuery(GameAthlete.class)
+                .eq(GameAthlete::getEventId, eventId)
+                .eq(GameAthlete::getAthleteCode, scoreItem.getAthleteCode())
+                .eq(GameAthlete::getStatus, "0")
+                .eq(GameAthlete::getDelFlag, "0");
+            GameAthlete athlete = gameAthleteMapper.selectOne(athleteWrapper);
+
+            if (athlete == null) {
+                Log.warn("未找到运动员: {}", scoreItem.getAthleteCode());
+                return false;
+            }
+
+            // 检查是否已存在成绩记录
+            LambdaQueryWrapper<GameScore> scoreWrapper = Wrappers.lambdaQuery(GameScore.class)
+                .eq(GameScore::getEventId, eventId)
+                .eq(GameScore::getProjectId, project.getProjectId())
+                .eq(GameScore::getAthleteId, athlete.getAthleteId());
+
+            GameScore existingScore = gameScoreMapper.selectOne(scoreWrapper);
+
+            // 处理成绩数据
+            BigDecimal scoreValue = null;
+            if (scoreItem.getScore() != null && !scoreItem.getScore().isEmpty()) {
+                try {
+                    // 处理时间格式的成绩(如1:23.213)
+                    if (scoreItem.getScore().contains(":")) {
+                        String[] timeParts = scoreItem.getScore().split(":");
+                        if (timeParts.length == 2) {
+                            double minutes = Double.parseDouble(timeParts[0]);
+                            double seconds = Double.parseDouble(timeParts[1]);
+                            scoreValue = BigDecimal.valueOf(minutes * 60 + seconds);
+                        }
+                    } else {
+                        scoreValue = BigDecimal.valueOf(Double.parseDouble(scoreItem.getScore()));
+                    }
+                } catch (NumberFormatException e) {
+                    Log.warn("解析成绩失败: {}", scoreItem.getScore(), e);
+                }
+            }
+
+            if (existingScore != null) {
+                // 更新现有记录
+                if (scoreValue != null) {
+                    existingScore.setIndividualPerformance(scoreValue);
+                }
+                if (scoreItem.getRank() != null) {
+                    existingScore.setScoreRank(scoreItem.getRank());
+                }
+                existingScore.setRemark("AVT电计设备上传");
+
+                return gameScoreMapper.updateById(existingScore) > 0;
+            } else {
+                // 创建新记录
+                GameScore newScore = new GameScore();
+                newScore.setEventId(eventId);
+                newScore.setProjectId(project.getProjectId());
+                newScore.setAthleteId(athlete.getAthleteId());
+                newScore.setTeamId(athlete.getTeamId());
+                if (scoreValue != null) {
+                    newScore.setIndividualPerformance(scoreValue);
+                }
+                if (scoreItem.getRank() != null) {
+                    newScore.setScoreRank(scoreItem.getRank());
+                }
+                newScore.setScoreType("individual");
+                newScore.setStatus("0");
+                newScore.setRemark("AVT电计设备上传");
+
+                return gameScoreMapper.insert(newScore) > 0;
+            }
+
+        } catch (Exception e) {
+            Log.error("保存AVT成绩记录失败: {}", e.getMessage(), e);
+            return false;
+        }
+    }
 }

+ 34 - 0
ruoyi-modules/ruoyi-game-event/src/main/resources/mapper/system/GameTeamMapper.xml

@@ -12,4 +12,38 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
         </foreach>
         AND del_flag = '0'
     </update>
+
+    <!-- 查询队伍列表并包含分组名 -->
+    <select id="selectVoListWithGroupName" resultType="org.dromara.system.domain.vo.GameTeamVo">
+        SELECT 
+            gt.team_id,
+            gt.event_id,
+            gt.rg_id,
+            grg.rg_name as rgName,
+            gt.team_name,
+            gt.team_code,
+            gt.leader,
+            gt.athlete_value as athleteValue,
+            gt.project_value as projectValue,
+            gt.athlete_num as athleteNum,
+            gt.number_range as numberRange,
+            gt.team_describe as teamDescribe,
+            gt.status,
+            gt.remark,
+            gt.create_time as createTime,
+            gt.update_time as updateTime
+        FROM game_team gt
+        LEFT JOIN game_rank_group grg ON gt.rg_id = grg.rg_id
+        WHERE gt.del_flag = '0' and gt.status = '0'
+        <if test="eventId != null">
+            AND gt.event_id = #{eventId}
+        </if>
+        <if test="teamName != null and teamName != ''">
+            AND gt.team_name LIKE CONCAT('%', #{teamName}, '%')
+        </if>
+        <if test="teamCode != null and teamCode != ''">
+            AND gt.team_code LIKE CONCAT('%', #{teamCode}, '%')
+        </if>
+        ORDER BY gt.team_id DESC
+    </select>
 </mapper>