3
0

2 Коммитууд 86010a8a80 ... 07d0971446

Эзэн SHA1 Мессеж Огноо
  zhou 07d0971446 Merge remote-tracking branch 'gogs/dev_zlt' into dev_zlt 2 өдөр өмнө
  zhou 5665619579 feat(game-event): 添加赛事项目进度查询功能 2 өдөр өмнө

+ 13 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/controller/GameEventController.java

@@ -20,6 +20,7 @@ import org.dromara.common.web.core.BaseController;
 import org.dromara.system.domain.bo.GameEventBo;
 import org.dromara.system.domain.constant.GameEventConstant;
 import org.dromara.system.domain.vo.GameEventVo;
+import org.dromara.system.domain.vo.ProjectProgressVo;
 import org.dromara.system.service.IGameEventService;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
@@ -153,4 +154,16 @@ public class GameEventController extends BaseController {
         return R.ok(gameEventService.countGameEvent(type));
     }
 
+    /**
+     * 获取赛事项目进度信息
+     *
+     * @param eventId 赛事ID
+     * @return 项目进度列表
+     */
+    @GetMapping("/projectProgress/{eventId}")
+    public R<List<ProjectProgressVo>> getProjectProgress(@NotNull(message = "赛事ID不能为空")
+                                                        @PathVariable Long eventId) {
+        return R.ok(gameEventService.getProjectProgress(eventId));
+    }
+
 }

+ 53 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/GroupProgressVo.java

@@ -0,0 +1,53 @@
+package org.dromara.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 组别进度视图对象
+ *
+ * @author zlt
+ * @date 2025-01-XX
+ */
+@Data
+public class GroupProgressVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 组别ID
+     */
+    private Long groupId;
+
+    /**
+     * 组别名称
+     */
+    private String groupName;
+
+    /**
+     * 组别开始时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date beginTime;
+
+    /**
+     * 组别结束时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date endTime;
+
+    /**
+     * 状态(0未开始 1进行中 2已完成)
+     */
+    private String status;
+
+    /**
+     * 状态描述
+     */
+    private String statusText;
+} 

+ 79 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/domain/vo/ProjectProgressVo.java

@@ -0,0 +1,79 @@
+package org.dromara.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 项目进度视图对象
+ *
+ * @author zlt
+ * @date 2025-01-XX
+ */
+@Data
+public class ProjectProgressVo implements Serializable {
+
+    @Serial
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 项目ID
+     */
+    private Long projectId;
+
+    /**
+     * 项目名称
+     */
+    private String projectName;
+
+    /**
+     * 项目类型
+     */
+    private String projectType;
+
+    /**
+     * 归类(0个人项目/1团体项目)
+     */
+    private String classification;
+
+    /**
+     * 比赛场地
+     */
+    private String location;
+
+    /**
+     * 项目开始时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date startTime;
+
+    /**
+     * 项目结束时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date endTime;
+
+    /**
+     * 状态(0未开始 1进行中 2已完成)
+     */
+    private String status;
+
+    /**
+     * 状态描述
+     */
+    private String statusText;
+
+    /**
+     * 组别信息列表
+     */
+    private List<GroupProgressVo> groups;
+
+    /**
+     * 项目进度百分比
+     */
+    private Integer progressPercentage;
+} 

+ 9 - 0
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/IGameEventService.java

@@ -8,6 +8,7 @@ import org.dromara.system.domain.bo.GameEventBo;
 import org.dromara.system.domain.bo.GenerateBibBo;
 import org.dromara.system.domain.vo.AthleteNumberTableVO;
 import org.dromara.system.domain.vo.GameEventVo;
+import org.dromara.system.domain.vo.ProjectProgressVo;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.util.Collection;
@@ -120,4 +121,12 @@ public interface IGameEventService {
     void exportNumberTable(HttpServletRequest request, HttpServletResponse response, Long eventId);
 
     void generateNumberBib(HttpServletResponse response, MultipartFile bgImage, MultipartFile logo, GenerateBibBo bibParam);
+
+    /**
+     * 获取赛事项目进度信息
+     *
+     * @param eventId 赛事ID
+     * @return 项目进度列表
+     */
+    List<ProjectProgressVo> getProjectProgress(Long eventId);
 }

+ 234 - 8
ruoyi-modules/ruoyi-game-event/src/main/java/org/dromara/system/service/impl/GameEventServiceImpl.java

@@ -1,5 +1,6 @@
 package org.dromara.system.service.impl;
 
+import cn.hutool.core.collection.CollectionUtil;
 import cn.hutool.core.img.FontUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -19,6 +20,7 @@ import com.itextpdf.text.pdf.PdfWriter;
 import jakarta.annotation.Resource;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotNull;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.output.ByteArrayOutputStream;
@@ -33,17 +35,13 @@ import org.dromara.common.mybatis.core.page.PageQuery;
 import org.dromara.common.mybatis.core.page.TableDataInfo;
 import org.dromara.common.redis.utils.RedisUtils;
 import org.dromara.system.domain.GameEvent;
-import org.dromara.system.domain.bo.GameAthleteBo;
-import org.dromara.system.domain.bo.GameEventBo;
-import org.dromara.system.domain.bo.GameTeamBo;
-import org.dromara.system.domain.bo.GenerateBibBo;
+import org.dromara.system.domain.GameEventGroup;
+import org.dromara.system.domain.PdfEntry;
+import org.dromara.system.domain.bo.*;
 import org.dromara.system.domain.constant.GameEventConstant;
 import org.dromara.system.domain.vo.*;
 import org.dromara.system.mapper.GameEventMapper;
-import org.dromara.system.service.IGameAthleteService;
-import org.dromara.system.service.IGameEventProjectService;
-import org.dromara.system.service.IGameEventService;
-import org.dromara.system.service.IGameTeamService;
+import org.dromara.system.service.*;
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -54,8 +52,13 @@ import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
 import java.io.*;
 import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
 /**
  * 赛事基本信息Service业务层处理
@@ -871,4 +874,227 @@ public class GameEventServiceImpl implements IGameEventService {
             return BaseFont.createFont(temp.getAbsolutePath(), BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
         }
     }
+
+    /**
+     * 获取赛事项目进度信息
+     *
+     * @param eventId 赛事ID
+     * @return 项目进度列表
+     */
+    @Override
+    public List<ProjectProgressVo> getProjectProgress(Long eventId) {
+        try {
+            // 1. 获取该赛事的所有项目
+            List<GameEventProjectVo> projects = gameEventProjectService.queryListByEventId(eventId);
+            if (CollectionUtils.isEmpty(projects)) {
+                return new ArrayList<>();
+            }
+
+            // 2. 获取所有项目的组别信息
+            GameEventGroupBo bo = new GameEventGroupBo();
+            bo.setEventId(eventId);
+            List<GameEventGroupVo> allGroups = gameEventGroupService.queryList(bo);
+            Map<Long, List<GameEventGroupVo>> projectGroupsMap = allGroups.stream()
+                .collect(Collectors.groupingBy(GameEventGroupVo::getProjectId));
+
+            // 3. 构建项目进度信息
+            List<ProjectProgressVo> progressList = new ArrayList<>();
+            Date currentTime = new Date();
+
+            for (GameEventProjectVo project : projects) {
+                ProjectProgressVo progressVo = new ProjectProgressVo();
+                progressVo.setProjectId(project.getProjectId());
+                progressVo.setProjectName(project.getProjectName());
+                progressVo.setProjectType(project.getProjectType());
+                progressVo.setClassification(project.getClassification());
+                progressVo.setLocation(project.getLocation());
+                progressVo.setStartTime(project.getStartTime());
+                progressVo.setEndTime(project.getEndTime());
+
+                // 获取该项目的组别信息
+                List<GameEventGroupVo> projectGroups = projectGroupsMap.get(project.getProjectId());
+                List<GroupProgressVo> groupProgressList = new ArrayList<>();
+
+                if (CollectionUtils.isEmpty(projectGroups)) {
+                    // 没有组别的项目,直接使用项目时间
+                    progressVo.setGroups(new ArrayList<>());
+                    progressVo.setStatus(getProjectStatus(project.getStartTime(), project.getEndTime(), currentTime));
+                    progressVo.setStatusText(getStatusText(progressVo.getStatus()));
+                    progressVo.setProgressPercentage(calculateProgressPercentage(project.getStartTime(), project.getEndTime(), currentTime));
+                } else {
+                    // 有组别的项目,处理每个组别
+                    for (GameEventGroupVo group : projectGroups) {
+                        GroupProgressVo groupProgress = new GroupProgressVo();
+                        groupProgress.setGroupId(group.getGroupId());
+                        groupProgress.setGroupName(group.getGroupName());
+                        groupProgress.setBeginTime(group.getBeginTime());
+                        groupProgress.setEndTime(group.getEndTime());
+                        groupProgress.setStatus(getProjectStatus(group.getBeginTime(), group.getEndTime(), currentTime));
+                        groupProgress.setStatusText(getStatusText(groupProgress.getStatus()));
+                        groupProgressList.add(groupProgress);
+                    }
+
+                    // 按组别完整开始时间排序
+                    groupProgressList.sort((a, b) -> {
+                        Date aTime = a.getBeginTime();
+                        Date bTime = b.getBeginTime();
+                        if (aTime == null && bTime == null) return 0;
+                        if (aTime == null) return 1;
+                        if (bTime == null) return -1;
+                        // 使用完整的日期时间进行比较
+                        return aTime.compareTo(bTime);
+                    });
+
+                    progressVo.setGroups(groupProgressList);
+
+                    // 项目整体状态:如果所有组别都完成则为完成,如果有进行中的则为进行中,否则为未开始
+                    String overallStatus = calculateOverallStatus(groupProgressList);
+                    progressVo.setStatus(overallStatus);
+                    progressVo.setStatusText(getStatusText(overallStatus));
+
+                    // 计算项目整体进度
+                    progressVo.setProgressPercentage(calculateOverallProgress(groupProgressList, currentTime));
+                }
+
+                progressList.add(progressVo);
+            }
+
+            // 4. 按项目完整时间排序(如果有组别,按最早组别开始时间排序)
+            progressList.sort((a, b) -> {
+                Date aStartTime = getEarliestStartTime(a);
+                Date bStartTime = getEarliestStartTime(b);
+                if (aStartTime == null && bStartTime == null) return 0;
+                if (aStartTime == null) return 1;
+                if (bStartTime == null) return -1;
+                // 使用完整的日期时间进行比较,确保按年、月、日、时、分、秒排序
+                return aStartTime.compareTo(bStartTime);
+            });
+
+            return progressList;
+
+        } catch (Exception e) {
+            log.error("获取赛事项目进度信息失败,eventId: {}", eventId, e);
+            return new ArrayList<>();
+        }
+    }
+
+    /**
+     * 获取项目状态
+     */
+    private String getProjectStatus(Date startTime, Date endTime, Date currentTime) {
+        if (startTime == null || endTime == null) {
+            return "0"; // 未开始
+        }
+
+        if (currentTime.before(startTime)) {
+            return "0"; // 未开始
+        } else if (currentTime.after(endTime)) {
+            return "2"; // 已完成
+        } else {
+            return "1"; // 进行中
+        }
+    }
+
+    /**
+     * 获取状态描述
+     */
+    private String getStatusText(String status) {
+        switch (status) {
+            case "0": return "未开始";
+            case "1": return "进行中";
+            case "2": return "已完成";
+            default: return "未知";
+        }
+    }
+
+    /**
+     * 计算项目进度百分比
+     */
+    private Integer calculateProgressPercentage(Date startTime, Date endTime, Date currentTime) {
+        if (startTime == null || endTime == null || currentTime == null) {
+            return 0;
+        }
+
+        if (currentTime.before(startTime)) {
+            return 0;
+        } else if (currentTime.after(endTime)) {
+            return 100;
+        } else {
+            long totalDuration = endTime.getTime() - startTime.getTime();
+            long elapsedDuration = currentTime.getTime() - startTime.getTime();
+            return (int) Math.round((double) elapsedDuration / totalDuration * 100);
+        }
+    }
+
+    /**
+     * 计算项目整体状态
+     */
+    private String calculateOverallStatus(List<GroupProgressVo> groups) {
+        if (CollectionUtils.isEmpty(groups)) {
+            return "0"; // 未开始
+        }
+
+        boolean hasCompleted = false;
+        boolean hasInProgress = false;
+
+        for (GroupProgressVo group : groups) {
+            if ("2".equals(group.getStatus())) {
+                hasCompleted = true;
+            } else if ("1".equals(group.getStatus())) {
+                hasInProgress = true;
+            }
+        }
+
+        if (hasInProgress) {
+            return "1"; // 进行中
+        } else if (hasCompleted && !hasInProgress) {
+            return "2"; // 已完成
+        } else {
+            return "0"; // 未开始
+        }
+    }
+
+    /**
+     * 计算项目整体进度
+     */
+    private Integer calculateOverallProgress(List<GroupProgressVo> groups, Date currentTime) {
+        if (CollectionUtils.isEmpty(groups)) {
+            return 0;
+        }
+
+        int totalProgress = 0;
+        for (GroupProgressVo group : groups) {
+            if (group.getBeginTime() != null && group.getEndTime() != null) {
+                totalProgress += calculateProgressPercentage(group.getBeginTime(), group.getEndTime(), currentTime);
+            }
+        }
+
+        return totalProgress / groups.size();
+    }
+
+        /**
+     * 获取项目的最早开始时间
+     * 优先使用组别时间,如果没有组别则使用项目时间
+     */
+    private Date getEarliestStartTime(ProjectProgressVo project) {
+        if (CollectionUtils.isEmpty(project.getGroups())) {
+            // 没有组别,直接返回项目开始时间
+            return project.getStartTime();
+        }
+        
+        // 有组别,找到最早的组别开始时间
+        Date earliestGroupTime = project.getGroups().stream()
+            .map(GroupProgressVo::getBeginTime)
+            .filter(Objects::nonNull)
+            .min(Date::compareTo)
+            .orElse(null);
+        
+        // 如果组别时间存在,与项目时间比较,返回较早的时间
+        if (earliestGroupTime != null && project.getStartTime() != null) {
+            return earliestGroupTime.before(project.getStartTime()) ? earliestGroupTime : project.getStartTime();
+        }
+        
+        // 如果组别时间不存在,返回项目时间
+        return earliestGroupTime != null ? earliestGroupTime : project.getStartTime();
+    }
 }

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

@@ -692,15 +692,25 @@ public class GameScoreServiceImpl implements IGameScoreService {
             })
             .toList();
 
-        // 更新排名
+        // 更新排名(支持并列排名)
+        int currentRank = 1;
         for (int i = 0; i < sortedByPoints.size(); i++) {
             GameScoreVo score = sortedByPoints.get(i);
-            int rank = i + 1;
+            int currentPoints = score.getScorePoint() != null ? score.getScorePoint() : 0;
+            
+            // 如果不是第一个,检查是否与前一个积分相同
+            if (i > 0) {
+                int previousPoints = sortedByPoints.get(i - 1).getScorePoint() != null ? 
+                    sortedByPoints.get(i - 1).getScorePoint() : 0;
+                if (currentPoints != previousPoints) {
+                    currentRank = i + 1;
+                }
+            }
 
             // 更新排名
             GameScoreBo updateBo = new GameScoreBo();
             updateBo.setScoreId(score.getScoreId());
-            updateBo.setScoreRank(rank);
+            updateBo.setScoreRank(currentRank);
             updateBo.setEventId(eventId);
             updateBo.setProjectId(projectId);
 
@@ -759,18 +769,27 @@ public class GameScoreServiceImpl implements IGameScoreService {
             .map(Integer::parseInt)
             .collect(Collectors.toList());
 
-        // 根据成绩排序结果分配积分和排名
+        // 根据成绩排序结果分配积分和排名(支持并列排名)
         Map<Long, Integer> teamPoints = new HashMap<>();
         Map<Long, Integer> teamRanks = new HashMap<>();
 
+        int currentRank = 1;
         for (int i = 0; i < sortedTeamsByPerformance.size(); i++) {
             Map.Entry<Long, BigDecimal> teamEntry = sortedTeamsByPerformance.get(i);
             Long teamId = teamEntry.getKey();
+            BigDecimal currentPerformance = teamEntry.getValue();
             int points = i < pointValues.size() ? pointValues.get(i) : 0;
-            int rank = i + 1;
+            
+            // 如果不是第一个,检查是否与前一个成绩相同
+            if (i > 0) {
+                BigDecimal previousPerformance = sortedTeamsByPerformance.get(i - 1).getValue();
+                if (currentPerformance.compareTo(previousPerformance) != 0) {
+                    currentRank = i + 1;
+                }
+            }
 
             teamPoints.put(teamId, points);
-            teamRanks.put(teamId, rank);
+            teamRanks.put(teamId, currentRank);
         }
 
         // 更新每个队伍中所有运动员的成绩记录

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

@@ -92,12 +92,12 @@ public class GameTeamServiceImpl implements IGameTeamService {
                     .filter(StringUtils::isNotBlank)
                     .ifPresent(athleteValue -> {
 //                        String[] projectIds = athleteValue.split(",");
-                        List<String> projectIds = JSONUtil.toList(athleteValue, String.class);
+                        List<String> athleteIds = JSONUtil.toList(athleteValue, String.class);
 //                        List<GameAthlete> athletes = gameAthleteMapper.selectList(
 //                            Wrappers.<GameAthlete>lambdaQuery()
 //                                .in(GameAthlete::getAthleteId, projectIds)
 //                                .select(GameAthlete::getName));
-                        vo.setAthleteList(projectIds);
+                        vo.setAthleteList(athleteIds);
 //                        vo.setAthleteValue(athletes.stream()
 //                            .map(GameAthlete::getName)
 //                            .filter(StringUtils::isNotBlank)