Codex Assistant
10 小时以前 ba94ceae1315174798ae1967ef62268c6d16cd5b
backend/src/main/java/com/rongyichuang/dashboard/service/DashboardService.java
@@ -1,18 +1,32 @@
package com.rongyichuang.dashboard.service;
import com.rongyichuang.activity.repository.ActivityRepository;
import com.rongyichuang.dashboard.dto.response.DashboardStatsResponse;
import com.rongyichuang.dashboard.dto.response.RegionRegistrationStat;
import com.rongyichuang.dashboard.dto.response.RegistrationTrendPoint;
import com.rongyichuang.judge.repository.JudgeRepository;
import com.rongyichuang.player.repository.ActivityPlayerRepository;
import com.rongyichuang.player.repository.PlayerRepository;
import com.rongyichuang.dashboard.dto.response.DashboardStatsResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * Dashboard 统计数据服务
 */
@Service
public class DashboardService {
    private static final int DEFAULT_TREND_DAYS = 15;
    private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    private static final String UNASSIGNED_REGION_NAME = "未选择区域";
    @Autowired
    private ActivityRepository activityRepository;
@@ -36,7 +50,7 @@
        long activeActivities = activityRepository.countActiveActivities();
        stats.setActiveActivities((int) activeActivities);
        
        // 参赛总人数(状态为1的选手)
        // 参赛总人数(状态为1的参赛选手)
        long totalPlayers = playerRepository.countByState(1);
        stats.setTotalPlayers((int) totalPlayers);
        
@@ -50,4 +64,98 @@
        
        return stats;
    }
    /**
     * 获取最近报名趋势(默认最近15天,仅统计第一阶段)
     */
    public List<RegistrationTrendPoint> getRegistrationTrend(Integer days) {
        int queryDays = (days == null || days <= 0) ? DEFAULT_TREND_DAYS : days;
        LocalDate today = LocalDate.now();
        LocalDate startDate = today.minusDays(queryDays - 1L);
        LocalDateTime startDateTime = startDate.atStartOfDay();
        List<Object[]> rawData = activityPlayerRepository.countFirstStageRegistrationsByDate(startDateTime);
        Map<String, Long> dataMap = new HashMap<>();
        for (Object[] row : rawData) {
            if (row == null || row.length < 2) {
                continue;
            }
            Object dateObj = row[0];
            LocalDate date;
            if (dateObj instanceof java.sql.Date sqlDate) {
                date = sqlDate.toLocalDate();
            } else if (dateObj instanceof LocalDate localDate) {
                date = localDate;
            } else {
                date = LocalDate.parse(dateObj.toString());
            }
            Long count = row[1] != null ? ((Number) row[1]).longValue() : 0L;
            dataMap.put(date.format(DATE_FORMATTER), count);
        }
        List<RegistrationTrendPoint> result = new ArrayList<>(queryDays);
        for (int i = 0; i < queryDays; i++) {
            LocalDate date = startDate.plusDays(i);
            String key = date.format(DATE_FORMATTER);
            Long count = dataMap.getOrDefault(key, 0L);
            result.add(new RegistrationTrendPoint(key, count));
        }
        return result;
    }
    /**
     * 获取区域报名分布(仅统计第一阶段,剔除非叶子区域)
     */
    public List<RegionRegistrationStat> getRegionRegistrationStats() {
        List<Object[]> rawData = activityPlayerRepository.countFirstStageRegistrationsByRegion();
        List<RegionRegistrationStat> stats = new ArrayList<>();
        for (Object[] row : rawData) {
            if (row == null || row.length < 4) {
                continue;
            }
            String regionId = null;
            if (row[0] != null) {
                Object regionIdObj = row[0];
                if (regionIdObj instanceof Number number) {
                    regionId = String.valueOf(number.longValue());
                } else {
                    regionId = regionIdObj.toString();
                }
            }
            String regionName = row[1] != null ? row[1].toString() : UNASSIGNED_REGION_NAME;
            // leaf_flag字段在不同驱动下的类型可能差异,需要统一转换
            Boolean leafFlag = null;
            Object leafObj = row[2];
            if (leafObj instanceof Number number) {
                leafFlag = number.intValue() == 1;
            } else if (leafObj instanceof Boolean bool) {
                leafFlag = bool;
            } else if (leafObj != null) {
                String leafText = leafObj.toString().trim().toLowerCase();
                if (!leafText.isEmpty()) {
                    if ("1".equals(leafText) || "true".equals(leafText)) {
                        leafFlag = true;
                    } else if ("0".equals(leafText) || "false".equals(leafText)) {
                        leafFlag = false;
                    }
                }
            }
            Long count = row[3] != null ? ((Number) row[3]).longValue() : 0L;
            if (Boolean.FALSE.equals(leafFlag)) {
                // 非叶子区域不参与统计
                continue;
            }
            if (regionName == null || regionName.isBlank()) {
                regionName = UNASSIGNED_REGION_NAME;
            }
            stats.add(new RegionRegistrationStat(regionId, regionName, leafFlag, count));
        }
        return stats;
    }
}