Browse Source

feat(game): 支持体质检测赛事成绩解析与展示

- 新增体质检测赛事类型判断逻辑
- 实现备注字段中resultData数据解析功能
- 添加健康检查成绩视图对象HealthCheckScoreVo
- 优化成绩导出时日期格式化处理
- 调整运动员列表流式处理方式
- 引入ObjectMapper用于JSON解析
- 定义健康检查赛事ID常量
- 完善计时类项目与普通项目的区分处理
zhou 1 day ago
parent
commit
e12748073b

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

@@ -0,0 +1,135 @@
+package org.dromara.system.domain.vo.app;
+
+import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
+import cn.idev.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.GameScore;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+
+/**
+ * 成绩视图对象 game_score
+ *
+ * @author zlt
+ * @date 2025-07-30
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = GameScore.class)
+public class HealthCheckScoreVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+    /**
+     * 成绩ID
+     */
+    @ExcelProperty(value = "成绩ID")
+    private Long scoreId;
+
+    /**
+     * 赛事ID
+     */
+    private Long eventId;
+    @ExcelProperty(value = "赛事")
+    private String eventName;
+
+    /**
+     * 项目ID
+     */
+//    @ExcelProperty(value = "项目ID")
+    private Long projectId;
+    @ExcelProperty(value = "项目")
+    private String projectName;
+
+    /**
+     * 运动员ID
+     */
+    private Long athleteId;
+    @ExcelProperty(value = "运动员")
+    private String athleteName;
+    /**
+     * 队伍ID
+     */
+    private Long teamId;
+    @ExcelProperty(value = "队伍")
+    private String teamName;
+
+    /**
+     * 成绩值
+     */
+//    @ExcelProperty(value = "个人成绩")
+    private BigDecimal individualPerformance;
+    @ExcelProperty(value = "团队成绩")
+    private BigDecimal teamPerformance;
+
+    /**
+     * 成绩类型
+     */
+    @ExcelProperty(value = "成绩类型")
+    private String scoreType;
+
+    /**
+     * 名次
+     */
+    @ExcelProperty(value = "名次")
+    private Integer scoreRank;
+
+    /**
+     * 积分
+     */
+    @ExcelProperty(value = "积分")
+    private Integer scorePoint;
+
+    /**
+     * 奖项(现用于检测成绩)
+     */
+    @ExcelProperty(value = "成绩")
+    private String award;
+
+    /**
+     * 领导加分
+     */
+    @ExcelProperty(value = "领导加分")
+    private Integer leaderPoint;
+
+    /**
+     * 额外加分
+     */
+    @ExcelProperty(value = "额外加分")
+    private Integer extraPoint;
+
+    /**
+     * 更新时间
+     */
+    @ExcelProperty(value = "更新时间")
+    private Date updateTime;
+
+    /**
+     * 成绩状态(0有效1无效)
+     */
+    @ExcelProperty(value = "成绩状态", converter = ExcelDictConvert.class)
+    @ExcelDictFormat(readConverterExp = "0=有效,1=无效")
+    private String statusFlag;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+//    @ExcelProperty(value = "状态", converter = ExcelDictConvert.class)
+//    @ExcelDictFormat(readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 备注
+     */
+    @ExcelProperty(value = "备注")
+    private String remark;
+
+
+}

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

@@ -1,6 +1,7 @@
 package org.dromara.system.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.dromara.common.core.utils.MapstructUtils;
 import org.dromara.common.core.utils.StringUtils;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
@@ -16,24 +17,22 @@ import org.dromara.system.domain.constant.ProjectClassification;
 import org.dromara.system.domain.constant.SortType;
 import org.dromara.system.domain.vo.*;
 import org.dromara.system.mapper.GameAthleteMapper;
-import org.dromara.system.mapper.GameEventProjectMapper;
-import org.dromara.system.service.IGameAthleteService;
-import org.dromara.system.service.IGameEventProjectService;
-import org.dromara.system.service.IGameTeamService;
+import org.dromara.system.service.*;
 import org.springframework.stereotype.Service;
 import org.dromara.system.domain.bo.GameScoreBo;
 import org.dromara.system.domain.GameScore;
 import org.dromara.system.mapper.GameScoreMapper;
-import org.dromara.system.service.IGameScoreService;
 
 import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.*;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 import jakarta.servlet.http.HttpServletResponse;
 import org.dromara.system.domain.bo.GameEventProjectBo;
 import org.dromara.system.domain.bo.GameTeamBo;
-import org.dromara.system.service.ISysDictTypeService;
 import org.dromara.system.domain.vo.SysDictDataVo;
 
 import java.net.URLEncoder;
@@ -57,10 +56,12 @@ public class GameScoreServiceImpl implements IGameScoreService {
     private final IGameTeamService gameTeamService;
     private final IGameAthleteService gameAthleteService;
     private final GameAthleteMapper gameAthleteMapper;
-    private final GameEventProjectMapper projectMapper;
+    private final IGameEventService gameEventService;
     private final IGameEventProjectService gameEventProjectService;
     private final ISysDictTypeService dictTypeService;
 
+    private static final Long HEALTH_CHECK = 1950743780869537804L;
+
 
     /**
      * 查询成绩
@@ -337,6 +338,9 @@ public class GameScoreServiceImpl implements IGameScoreService {
         // 获取项目信息,判断是否为计时类项目
         GameEventProjectVo project = gameEventProjectService.queryById(projectId);
         boolean isTiming = isTimingProject(project);
+        // 获取默认赛事,判断默认赛事是否为体质检测
+        GameEventVo defaultEvent = gameEventService.getDefaultEvent();
+        boolean isHealthCheck = defaultEvent.getEventId().equals(HEALTH_CHECK) && defaultEvent.getEventId().equals(eventId);
 
         // 查询参与该项目的运动员
         List<GameAthleteVo> athletes = gameAthleteService.queryListByEventIdAndProjectId(eventId, projectId, searchValue);
@@ -379,6 +383,20 @@ public class GameScoreServiceImpl implements IGameScoreService {
                 if (isTiming && score.getIndividualPerformance() != null) {
                     String timeFormat = convertDecimalToTimeScore(score.getIndividualPerformance());
                     data.put("individualPerformance", timeFormat != null ? timeFormat : score.getIndividualPerformance());
+                } else if (isHealthCheck){
+                    if (score.getRemark() != null && score.getRemark().contains("resultData")){
+                        try {
+                            ObjectMapper objectMapper = new ObjectMapper();
+                            Map remarkMap = objectMapper.readValue(score.getRemark(), Map.class);
+                            String resultData = remarkMap.get("resultData").toString();
+                            data.put("individualPerformance", resultData);
+                        } catch (Exception e) {
+                            // 处理解析异常
+                            log.error("解析remark失败", e);
+                        }
+                    }else{
+                        data.put("individualPerformance", 0.0);
+                    }
                 } else {
                     data.put("individualPerformance", score.getIndividualPerformance());
                 }
@@ -439,7 +457,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
             // 获取项目信息,判断是否为计时类项目
             GameEventProjectVo project = gameEventProjectService.queryById(projectId);
             boolean isTiming = isTimingProject(project);
-            
+
             if (score != null) {
                 data.put("scoreId", score.getScoreId());
                 data.put("scorePoint", score.getScorePoint());
@@ -543,7 +561,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
             // 过滤出属于指定队伍的运动员
             List<GameAthleteVo> relevantAthletes = teamAthletes.stream()
                 .filter(athlete -> athlete.getTeamId() != null && athlete.getTeamId().equals(bo.getTeamId()))
-                .collect(Collectors.toList());
+                .toList();
 
             log.info("队伍 {} 的运动员数量: {}", bo.getTeamId(), relevantAthletes.size());
 
@@ -795,7 +813,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
         List<Integer> pointValues = Arrays.stream(scoreValue.split(","))
             .map(String::trim)
             .map(Integer::parseInt)
-            .collect(Collectors.toList());
+            .toList();
 
         // 根据成绩排序结果分配积分和排名(支持并列排名)
         Map<Long, Integer> teamPoints = new HashMap<>();
@@ -1012,7 +1030,7 @@ public class GameScoreServiceImpl implements IGameScoreService {
                 // 设置成绩信息 - 如果是计时类项目,需要特殊处理
                 BigDecimal individualPerf = convertToBigDecimal(score.getIndividualPerformance());
                 BigDecimal teamPerf = convertToBigDecimal(score.getTeamPerformance());
-                
+
                 // 注意:AppScoreVo 的字段类型是 BigDecimal,但如果是计时类项目,我们仍然存储 BigDecimal
                 // 前端可以根据项目类型决定如何显示
                 vo.setIndividualPerformance(individualPerf);
@@ -1271,7 +1289,20 @@ public class GameScoreServiceImpl implements IGameScoreService {
     private void createCellWithStyle(Row row, int colIndex, Object value, CellStyle style) {
         Cell cell = row.createCell(colIndex);
 
-        if (value instanceof Integer) {
+        if (value instanceof LocalDateTime) {
+            // 转换为字符串并设置特定格式
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+            String formattedDate = ((LocalDateTime) value).format(formatter);
+            cell.setCellValue(formattedDate);
+        } else if (value instanceof Date) {
+            // 如果是Date类型,先转换为LocalDateTime再格式化
+            LocalDateTime localDateTime = ((Date) value).toInstant()
+                .atZone(ZoneId.systemDefault())
+                .toLocalDateTime();
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+            String formattedDate = localDateTime.format(formatter);
+            cell.setCellValue(formattedDate);
+        } else if (value instanceof Integer) {
             cell.setCellValue((Integer) value);
         } else if (value instanceof String) {
             cell.setCellValue((String) value);
@@ -1614,6 +1645,11 @@ public class GameScoreServiceImpl implements IGameScoreService {
         GameEventProjectVo project = gameEventProjectService.queryById(projectId);
         boolean isTiming = isTimingProject(project);
 
+        // 获取默认赛事,判断默认赛事是否为体质检测
+        GameEventVo defaultEvent = gameEventService.getDefaultEvent();
+        boolean isHealthCheck = defaultEvent.getEventId().equals(HEALTH_CHECK) && defaultEvent.getEventId().equals(eventId);
+
+
         // 查询参与该项目的所有运动员(不分页)
         List<GameAthleteVo> athletes = gameAthleteService.queryListByEventIdAndProjectId(eventId, projectId, null);
 
@@ -1649,6 +1685,20 @@ public class GameScoreServiceImpl implements IGameScoreService {
                 if (isTiming && score.getIndividualPerformance() != null) {
                     String timeFormat = convertDecimalToTimeScore(score.getIndividualPerformance());
                     data.put("individualPerformance", timeFormat != null ? timeFormat : score.getIndividualPerformance());
+                }else if (isHealthCheck){
+                    if (score.getRemark() != null && score.getRemark().contains("resultData")){
+                        try {
+                            ObjectMapper objectMapper = new ObjectMapper();
+                            Map remarkMap = objectMapper.readValue(score.getRemark(), Map.class);
+                            String resultData = remarkMap.get("resultData").toString();
+                            data.put("individualPerformance", resultData);
+                        } catch (Exception e) {
+                            // 处理解析异常
+                            log.error("解析remark失败", e);
+                        }
+                    }else{
+                        data.put("individualPerformance", 0.0);
+                    }
                 } else {
                     data.put("individualPerformance", score.getIndividualPerformance());
                 }