package com.rongyichuang.player.service;
|
|
import com.rongyichuang.activity.entity.Activity;
|
import com.rongyichuang.activity.entity.ActivityPlayerRating;
|
import com.rongyichuang.activity.repository.ActivityPlayerRatingRepository;
|
import com.rongyichuang.activity.repository.ActivityRepository;
|
import com.rongyichuang.judge.entity.Judge;
|
import com.rongyichuang.judge.repository.JudgeRepository;
|
import com.rongyichuang.player.dto.response.ProjectStageTimelineItemResponse;
|
import com.rongyichuang.player.dto.response.ProjectStageTimelineResponse;
|
import com.rongyichuang.player.dto.response.StageJudgeRatingDetailResponse;
|
import com.rongyichuang.player.dto.response.StageJudgeRatingItemResponse;
|
import com.rongyichuang.player.entity.ActivityPlayer;
|
import com.rongyichuang.player.repository.ActivityPlayerRepository;
|
import org.slf4j.Logger;
|
import org.slf4j.LoggerFactory;
|
import org.springframework.stereotype.Service;
|
|
import java.math.BigDecimal;
|
import java.math.RoundingMode;
|
import java.time.LocalDateTime;
|
import java.time.format.DateTimeFormatter;
|
import java.util.ArrayList;
|
import java.util.Collection;
|
import java.util.Comparator;
|
import java.util.HashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
import java.util.Optional;
|
import java.util.Set;
|
import java.util.stream.Collectors;
|
|
/**
|
* 项目阶段评分相关服务
|
*/
|
@Service
|
public class ProjectStageRatingService {
|
|
private static final Logger log = LoggerFactory.getLogger(ProjectStageRatingService.class);
|
|
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
|
|
private final ActivityPlayerRepository activityPlayerRepository;
|
private final ActivityRepository activityRepository;
|
private final ActivityPlayerRatingRepository activityPlayerRatingRepository;
|
private final JudgeRepository judgeRepository;
|
|
public ProjectStageRatingService(ActivityPlayerRepository activityPlayerRepository,
|
ActivityRepository activityRepository,
|
ActivityPlayerRatingRepository activityPlayerRatingRepository,
|
JudgeRepository judgeRepository) {
|
this.activityPlayerRepository = activityPlayerRepository;
|
this.activityRepository = activityRepository;
|
this.activityPlayerRatingRepository = activityPlayerRatingRepository;
|
this.judgeRepository = judgeRepository;
|
}
|
|
/**
|
* 获取项目在各阶段的时间轴与评分概况
|
*/
|
public ProjectStageTimelineResponse getProjectStageTimeline(Long activityPlayerId) {
|
ActivityPlayer current = activityPlayerRepository.findById(activityPlayerId)
|
.orElseThrow(() -> new IllegalArgumentException("未找到参赛记录,ID: " + activityPlayerId));
|
|
Long activityId = current.getActivityId();
|
Long playerId = current.getPlayerId();
|
|
ProjectStageTimelineResponse response = new ProjectStageTimelineResponse();
|
response.setActivityId(activityId);
|
|
Activity activity = activityRepository.findActivityById(activityId);
|
if (activity != null) {
|
response.setActivityName(activity.getName());
|
}
|
|
List<Activity> stages = new ArrayList<>(activityRepository.findByPidAndStateOrderBySortOrderAsc(activityId, 1));
|
|
Map<Long, ActivityPlayer> stagePlayerMap = activityPlayerRepository
|
.findByActivityIdAndPlayerIdOrderByCreateTimeDesc(activityId, playerId)
|
.stream()
|
.filter(ap -> ap.getStageId() != null)
|
.collect(Collectors.toMap(ActivityPlayer::getStageId, ap -> ap, (existing, replacement) -> existing));
|
|
// 确保当前阶段包含在时间轴中
|
if (current.getStageId() != null && !stagePlayerMap.containsKey(current.getStageId())) {
|
stagePlayerMap.put(current.getStageId(), current);
|
}
|
|
// 如果阶段列表中缺少已参赛阶段,补全它们
|
Set<Long> stageIdsInList = stages.stream().map(Activity::getId).collect(Collectors.toSet());
|
for (Long stageId : stagePlayerMap.keySet()) {
|
if (!stageIdsInList.contains(stageId)) {
|
Activity stage = activityRepository.findActivityById(stageId);
|
if (stage != null) {
|
stages.add(stage);
|
stageIdsInList.add(stageId);
|
}
|
}
|
}
|
|
// 按 sortOrder 及创建时间排序,确保展示顺序
|
stages.sort(Comparator
|
.comparing((Activity stage) -> Optional.ofNullable(stage.getSortOrder()).orElse(Integer.MAX_VALUE))
|
.thenComparing(Activity::getId));
|
|
List<ProjectStageTimelineItemResponse> items = new ArrayList<>();
|
for (Activity stage : stages) {
|
ProjectStageTimelineItemResponse item = new ProjectStageTimelineItemResponse();
|
item.setStageId(stage.getId());
|
item.setStageName(stage.getName());
|
item.setMatchTime(formatDateTime(stage.getMatchTime()));
|
item.setSortOrder(stage.getSortOrder());
|
|
ActivityPlayer stagePlayer = stagePlayerMap.get(stage.getId());
|
boolean participated = stagePlayer != null;
|
item.setParticipated(participated);
|
|
if (participated) {
|
item.setActivityPlayerId(stagePlayer.getId());
|
applyRatingMetrics(item, stagePlayer.getId());
|
} else {
|
item.setHasRating(false);
|
item.setRatingCount(0);
|
}
|
|
items.add(item);
|
}
|
|
response.setStages(items);
|
return response;
|
}
|
|
/**
|
* 获取指定阶段的评委评分详情
|
*/
|
public StageJudgeRatingDetailResponse getStageJudgeRatings(Long activityPlayerId) {
|
ActivityPlayer stagePlayer = activityPlayerRepository.findById(activityPlayerId)
|
.orElseThrow(() -> new IllegalArgumentException("未找到参赛记录,ID: " + activityPlayerId));
|
|
StageJudgeRatingDetailResponse response = new StageJudgeRatingDetailResponse();
|
response.setActivityPlayerId(activityPlayerId);
|
|
Activity stage = null;
|
if (stagePlayer.getStageId() != null) {
|
stage = activityRepository.findActivityById(stagePlayer.getStageId());
|
}
|
|
if (stage != null) {
|
response.setStageId(stage.getId());
|
response.setStageName(stage.getName());
|
response.setMatchTime(formatDateTime(stage.getMatchTime()));
|
} else {
|
response.setStageId(stagePlayer.getStageId());
|
response.setStageName("阶段信息缺失");
|
}
|
|
List<ActivityPlayerRating> ratings = activityPlayerRatingRepository.findByActivityPlayerId(activityPlayerId);
|
Map<Long, ActivityPlayerRating> latestRatingByJudge = new HashMap<>();
|
|
for (ActivityPlayerRating rating : ratings) {
|
Long judgeId = rating.getJudgeId();
|
if (judgeId == null) {
|
continue;
|
}
|
ActivityPlayerRating existing = latestRatingByJudge.get(judgeId);
|
if (existing == null) {
|
latestRatingByJudge.put(judgeId, rating);
|
} else {
|
LocalDateTime existingTime = existing.getUpdateTime();
|
LocalDateTime currentTime = rating.getUpdateTime();
|
if (existingTime == null || (currentTime != null && currentTime.isAfter(existingTime))) {
|
latestRatingByJudge.put(judgeId, rating);
|
}
|
}
|
}
|
|
Collection<ActivityPlayerRating> effectiveRatings = latestRatingByJudge.values();
|
List<BigDecimal> validScores = effectiveRatings.stream()
|
.map(ActivityPlayerRating::getTotalScore)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toList());
|
|
int ratingCount = validScores.size();
|
response.setRatingCount(ratingCount);
|
if (ratingCount > 0) {
|
BigDecimal sum = validScores.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
BigDecimal avg = sum.divide(BigDecimal.valueOf(ratingCount), 2, RoundingMode.HALF_UP);
|
response.setAverageScore(avg.doubleValue());
|
}
|
|
if (!effectiveRatings.isEmpty()) {
|
Set<Long> judgeIds = effectiveRatings.stream()
|
.map(ActivityPlayerRating::getJudgeId)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toSet());
|
|
Map<Long, String> judgeNameMap = new HashMap<>();
|
if (!judgeIds.isEmpty()) {
|
List<Judge> judges = judgeRepository.findAllById(judgeIds);
|
for (Judge judge : judges) {
|
judgeNameMap.put(judge.getId(), judge.getName());
|
}
|
}
|
|
List<StageJudgeRatingItemResponse> judgeItems = effectiveRatings.stream()
|
.sorted(Comparator.comparing(ActivityPlayerRating::getUpdateTime, Comparator.nullsLast(LocalDateTime::compareTo)).reversed())
|
.map(rating -> {
|
StageJudgeRatingItemResponse item = new StageJudgeRatingItemResponse();
|
Long judgeId = rating.getJudgeId();
|
item.setJudgeId(judgeId);
|
item.setJudgeName(judgeNameMap.getOrDefault(judgeId, "未知评委"));
|
if (rating.getTotalScore() != null) {
|
item.setTotalScore(rating.getTotalScore().doubleValue());
|
}
|
item.setFeedback(rating.getFeedback());
|
item.setRatingTime(formatDateTime(rating.getUpdateTime()));
|
return item;
|
})
|
.collect(Collectors.toList());
|
|
response.setJudgeRatings(judgeItems);
|
}
|
|
return response;
|
}
|
|
private void applyRatingMetrics(ProjectStageTimelineItemResponse item, Long stageActivityPlayerId) {
|
List<ActivityPlayerRating> ratings = activityPlayerRatingRepository
|
.findCompletedRatingsByActivityPlayerId(stageActivityPlayerId);
|
|
List<BigDecimal> validScores = ratings.stream()
|
.map(ActivityPlayerRating::getTotalScore)
|
.filter(Objects::nonNull)
|
.collect(Collectors.toList());
|
|
int ratingCount = validScores.size();
|
item.setRatingCount(ratingCount);
|
item.setHasRating(ratingCount > 0);
|
|
if (ratingCount > 0) {
|
BigDecimal sum = validScores.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
|
BigDecimal avg = sum.divide(BigDecimal.valueOf(ratingCount), 2, RoundingMode.HALF_UP);
|
item.setAverageScore(avg.doubleValue());
|
}
|
|
ratings.stream()
|
.map(ActivityPlayerRating::getUpdateTime)
|
.filter(Objects::nonNull)
|
.max(LocalDateTime::compareTo)
|
.ifPresent(time -> item.setLatestRatingTime(formatDateTime(time)));
|
}
|
|
private String formatDateTime(LocalDateTime time) {
|
if (time == null) {
|
return null;
|
}
|
return DATE_TIME_FORMATTER.format(time);
|
}
|
}
|