| | |
| | | package com.rongyichuang.player.service; |
| | | |
| | | import com.rongyichuang.activity.entity.ActivityPlayerRating; |
| | | import com.rongyichuang.activity.entity.ActivityPlayerRatingItem; |
| | | import com.rongyichuang.activity.repository.ActivityPlayerRatingRepository; |
| | | import com.rongyichuang.activity.repository.ActivityPlayerRatingItemRepository; |
| | | import com.rongyichuang.common.util.UserContextUtil; |
| | | import com.rongyichuang.judge.entity.Judge; |
| | | import com.rongyichuang.judge.repository.JudgeRepository; |
| | | import com.rongyichuang.player.dto.input.ActivityPlayerRatingInput; |
| | | import com.rongyichuang.player.dto.input.ActivityPlayerRatingItemInput; |
| | | import com.rongyichuang.player.dto.response.JudgeRatingStatusResponse; |
| | | import com.rongyichuang.player.dto.response.CurrentJudgeRatingResponse; |
| | | import com.rongyichuang.player.dto.response.CurrentJudgeInfoResponse; |
| | | import com.rongyichuang.rating.entity.RatingItem; |
| | | import com.rongyichuang.rating.repository.RatingItemRepository; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | | import java.math.BigDecimal; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.Optional; |
| | | |
| | | @Service |
| | | public class ActivityPlayerRatingService { |
| | |
| | | |
| | | @Autowired |
| | | private JdbcTemplate jdbcTemplate; |
| | | |
| | | @Autowired |
| | | private ActivityPlayerRatingRepository activityPlayerRatingRepository; |
| | | |
| | | @Autowired |
| | | private ActivityPlayerRatingItemRepository activityPlayerRatingItemRepository; |
| | | |
| | | @Autowired |
| | | private RatingItemRepository ratingItemRepository; |
| | | |
| | | @Autowired |
| | | private JudgeRepository judgeRepository; |
| | | |
| | | @Autowired |
| | | private UserContextUtil userContextUtil; |
| | | |
| | | @Transactional |
| | | public boolean saveRating(ActivityPlayerRatingInput input) { |
| | | try { |
| | | log.info("开始保存评分,activityPlayerId: {}", input.getActivityPlayerId()); |
| | | log.info("开始保存多评委评分,activityPlayerId: {}", input.getActivityPlayerId()); |
| | | |
| | | // 先删除已有的评分记录(如果存在) |
| | | String deleteSql = "DELETE FROM t_activity_player_rating_item WHERE activity_player_id = ?"; |
| | | int deletedCount = jdbcTemplate.update(deleteSql, input.getActivityPlayerId()); |
| | | log.info("删除已有评分记录: {} 条", deletedCount); |
| | | |
| | | // 插入新的评分记录 |
| | | String insertSql = "INSERT INTO t_activity_player_rating_item " + |
| | | "(activity_player_id, rating_item_id, score, comment, create_time, update_time) " + |
| | | "VALUES (?, ?, ?, ?, ?, ?)"; |
| | | |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | int totalInserted = 0; |
| | | |
| | | for (ActivityPlayerRatingItemInput ratingItem : input.getRatings()) { |
| | | int inserted = jdbcTemplate.update(insertSql, |
| | | input.getActivityPlayerId(), |
| | | ratingItem.getItemId(), |
| | | ratingItem.getScore(), |
| | | input.getComment(), |
| | | now, |
| | | now |
| | | ); |
| | | totalInserted += inserted; |
| | | log.info("保存评分项目: itemId={}, score={}", ratingItem.getItemId(), ratingItem.getScore()); |
| | | // 获取当前评委信息 |
| | | Long currentJudgeId = userContextUtil.getCurrentJudgeId(); |
| | | if (currentJudgeId == null) { |
| | | throw new RuntimeException("当前用户不是评委,无法进行评分"); |
| | | } |
| | | |
| | | log.info("评分保存完成,共插入 {} 条记录", totalInserted); |
| | | Long activityPlayerId = input.getActivityPlayerId(); |
| | | |
| | | // 查询 activity_id, player_id |
| | | String queryPlayerSql = "SELECT activity_id, player_id FROM t_activity_player WHERE id = ?"; |
| | | Map<String, Object> playerData = jdbcTemplate.queryForMap(queryPlayerSql, activityPlayerId); |
| | | Long activityId = (Long) playerData.get("activity_id"); |
| | | Long playerId = (Long) playerData.get("player_id"); |
| | | log.info("查询到的数据 - activityId: {}, playerId: {}, judgeId: {}", activityId, playerId, currentJudgeId); |
| | | |
| | | // 验证评委是否有权限评分此活动 |
| | | if (!userContextUtil.isCurrentUserJudgeForActivity(activityId)) { |
| | | throw new RuntimeException("当前评委无权限评分此活动"); |
| | | } |
| | | |
| | | // 查询活动的评分模板ID |
| | | String queryActivitySql = "SELECT rating_scheme_id FROM t_activity WHERE id = ?"; |
| | | Long ratingSchemeId = jdbcTemplate.queryForObject(queryActivitySql, Long.class, activityId); |
| | | log.info("查询到的ratingSchemeId: {}", ratingSchemeId); |
| | | |
| | | if (ratingSchemeId == null) { |
| | | throw new RuntimeException("活动未配置评分模板,activityId: " + activityId); |
| | | } |
| | | |
| | | // 查找或创建ActivityPlayerRating记录 |
| | | Optional<ActivityPlayerRating> existingRating = activityPlayerRatingRepository |
| | | .findByActivityPlayerIdAndJudgeId(activityPlayerId, currentJudgeId); |
| | | |
| | | ActivityPlayerRating rating; |
| | | if (existingRating.isPresent()) { |
| | | rating = existingRating.get(); |
| | | log.info("找到已有评分记录,ID: {}", rating.getId()); |
| | | // 删除已有的评分项 |
| | | activityPlayerRatingItemRepository.deleteByActivityPlayerRatingId(rating.getId()); |
| | | } else { |
| | | // 创建新的评分记录 |
| | | rating = new ActivityPlayerRating(activityId, activityPlayerId, playerId, currentJudgeId, ratingSchemeId); |
| | | rating = activityPlayerRatingRepository.save(rating); |
| | | log.info("创建新的评分记录,ID: {}", rating.getId()); |
| | | } |
| | | |
| | | // 保存评分项 |
| | | BigDecimal totalScore = BigDecimal.ZERO; |
| | | for (ActivityPlayerRatingItemInput ratingItemInput : input.getRatings()) { |
| | | Long itemId = ratingItemInput.getItemId(); |
| | | BigDecimal score = BigDecimal.valueOf(ratingItemInput.getScore()); |
| | | |
| | | // 查询评分项信息 |
| | | Optional<RatingItem> ratingItemOpt = ratingItemRepository.findById(itemId); |
| | | if (ratingItemOpt.isEmpty()) { |
| | | log.warn("评分项不存在,itemId: {}", itemId); |
| | | continue; |
| | | } |
| | | |
| | | RatingItem ratingItem = ratingItemOpt.get(); |
| | | |
| | | // 创建评分项记录 |
| | | ActivityPlayerRatingItem ratingItemEntity = new ActivityPlayerRatingItem( |
| | | rating.getId(), |
| | | itemId, |
| | | ratingItem.getName(), |
| | | BigDecimal.ONE, // 默认权重为1 |
| | | BigDecimal.valueOf(ratingItem.getMaxScore()), |
| | | score |
| | | ); |
| | | ratingItemEntity.setRemark(input.getComment()); |
| | | |
| | | activityPlayerRatingItemRepository.save(ratingItemEntity); |
| | | |
| | | // 累加加权得分 |
| | | if (ratingItemEntity.getWeightedScore() != null) { |
| | | totalScore = totalScore.add(ratingItemEntity.getWeightedScore()); |
| | | } |
| | | |
| | | log.info("保存评分项目: itemId={}, score={}, weightedScore={}", |
| | | itemId, score, ratingItemEntity.getWeightedScore()); |
| | | } |
| | | |
| | | // 更新总分和状态 |
| | | rating.setTotalScore(totalScore); |
| | | rating.setStatus(1); // 已评分 |
| | | rating.setRemark(input.getComment()); |
| | | activityPlayerRatingRepository.save(rating); |
| | | |
| | | log.info("评分保存完成,总分: {}", totalScore); |
| | | return true; |
| | | |
| | | } catch (Exception e) { |
| | | log.error("保存评分失败", e); |
| | | throw new RuntimeException("保存评分失败: " + e.getMessage()); |
| | | log.error("保存评分失败,异常类型: {}, 异常信息: {}", e.getClass().getSimpleName(), e.getMessage(), e); |
| | | e.printStackTrace(); |
| | | throw new RuntimeException("保存评分失败: " + e.getClass().getSimpleName() + " - " + e.getMessage(), e); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取指定活动选手的所有评委评分 |
| | | */ |
| | | public List<ActivityPlayerRating> getAllRatingsForPlayer(Long activityPlayerId) { |
| | | return activityPlayerRatingRepository.findByActivityPlayerId(activityPlayerId); |
| | | } |
| | | |
| | | /** |
| | | * 获取指定活动选手的平均分 |
| | | */ |
| | | public BigDecimal getAverageScoreForPlayer(Long activityPlayerId) { |
| | | List<ActivityPlayerRating> ratings = activityPlayerRatingRepository |
| | | .findCompletedRatingsByActivityPlayerId(activityPlayerId); |
| | | |
| | | if (ratings.isEmpty()) { |
| | | return BigDecimal.ZERO; |
| | | } |
| | | |
| | | BigDecimal totalScore = ratings.stream() |
| | | .map(ActivityPlayerRating::getTotalScore) |
| | | .filter(score -> score != null) |
| | | .reduce(BigDecimal.ZERO, BigDecimal::add); |
| | | |
| | | return totalScore.divide(BigDecimal.valueOf(ratings.size()), 2, BigDecimal.ROUND_HALF_UP); |
| | | } |
| | | |
| | | /** |
| | | * 获取当前评委对指定选手的评分 |
| | | */ |
| | | public CurrentJudgeRatingResponse getCurrentJudgeRating(Long activityPlayerId) { |
| | | Long currentJudgeId = userContextUtil.getCurrentJudgeId(); |
| | | if (currentJudgeId == null) { |
| | | return null; |
| | | } |
| | | |
| | | Optional<ActivityPlayerRating> ratingOpt = activityPlayerRatingRepository |
| | | .findByActivityPlayerIdAndJudgeId(activityPlayerId, currentJudgeId); |
| | | |
| | | if (!ratingOpt.isPresent()) { |
| | | return null; |
| | | } |
| | | |
| | | ActivityPlayerRating rating = ratingOpt.get(); |
| | | CurrentJudgeRatingResponse response = new CurrentJudgeRatingResponse(); |
| | | response.setId(rating.getId()); |
| | | response.setTotalScore(rating.getTotalScore()); |
| | | response.setStatus(rating.getStatus()); |
| | | response.setRemark(rating.getRemark()); |
| | | |
| | | // 获取评分项 |
| | | List<ActivityPlayerRatingItem> items = activityPlayerRatingItemRepository |
| | | .findByActivityPlayerRatingId(rating.getId()); |
| | | |
| | | List<CurrentJudgeRatingResponse.CurrentJudgeRatingItemResponse> itemResponses = items.stream() |
| | | .map(item -> new CurrentJudgeRatingResponse.CurrentJudgeRatingItemResponse( |
| | | item.getRatingItemId(), |
| | | item.getRatingItemName(), |
| | | item.getScore(), |
| | | item.getWeightedScore() |
| | | )) |
| | | .collect(java.util.stream.Collectors.toList()); |
| | | |
| | | response.setItems(itemResponses); |
| | | return response; |
| | | } |
| | | |
| | | /** |
| | | * 检查当前评委是否已对指定选手评分 |
| | | */ |
| | | public boolean hasCurrentJudgeRated(Long activityPlayerId) { |
| | | Long currentJudgeId = userContextUtil.getCurrentJudgeId(); |
| | | if (currentJudgeId == null) { |
| | | return false; |
| | | } |
| | | |
| | | return activityPlayerRatingRepository.existsByActivityPlayerIdAndJudgeId(activityPlayerId, currentJudgeId); |
| | | } |
| | | |
| | | /** |
| | | * 获取指定选手的所有评委评分状态 |
| | | */ |
| | | public List<JudgeRatingStatusResponse> getAllJudgeRatingsForPlayer(Long activityPlayerId) { |
| | | // 首先获取活动ID |
| | | String activitySql = "SELECT activity_id FROM t_activity_player WHERE id = ?"; |
| | | Long activityId = jdbcTemplate.queryForObject(activitySql, Long.class, activityPlayerId); |
| | | |
| | | if (activityId == null) { |
| | | throw new RuntimeException("未找到活动选手记录,activityPlayerId: " + activityPlayerId); |
| | | } |
| | | |
| | | // 获取活动的所有评委 |
| | | String judgesSql = "SELECT j.id, j.name FROM t_judge j " + |
| | | "JOIN t_activity_judge aj ON j.id = aj.judge_id " + |
| | | "WHERE aj.activity_id = ? ORDER BY j.name"; |
| | | |
| | | List<Map<String, Object>> judgeRows = jdbcTemplate.queryForList(judgesSql, activityId); |
| | | |
| | | Long currentJudgeId = userContextUtil.getCurrentJudgeId(); |
| | | |
| | | return judgeRows.stream().map(row -> { |
| | | Long judgeId = ((Number) row.get("id")).longValue(); |
| | | String judgeName = (String) row.get("name"); |
| | | |
| | | // 查找该评委的评分 |
| | | Optional<ActivityPlayerRating> ratingOpt = activityPlayerRatingRepository |
| | | .findByActivityPlayerIdAndJudgeId(activityPlayerId, judgeId); |
| | | |
| | | BigDecimal totalScore = null; |
| | | Integer status = 0; |
| | | |
| | | if (ratingOpt.isPresent()) { |
| | | ActivityPlayerRating rating = ratingOpt.get(); |
| | | totalScore = rating.getTotalScore(); |
| | | status = rating.getStatus(); |
| | | } |
| | | |
| | | Boolean isCurrentJudge = judgeId.equals(currentJudgeId); |
| | | |
| | | return new JudgeRatingStatusResponse(judgeId, judgeName, totalScore, status, isCurrentJudge); |
| | | }).collect(java.util.stream.Collectors.toList()); |
| | | } |
| | | |
| | | /** |
| | | * 获取当前评委信息 |
| | | */ |
| | | public CurrentJudgeInfoResponse getCurrentJudgeInfo() { |
| | | Optional<Judge> currentJudgeOpt = userContextUtil.getCurrentJudge(); |
| | | if (!currentJudgeOpt.isPresent()) { |
| | | return null; |
| | | } |
| | | |
| | | Judge currentJudge = currentJudgeOpt.get(); |
| | | return new CurrentJudgeInfoResponse( |
| | | currentJudge.getId(), |
| | | currentJudge.getName(), |
| | | currentJudge.getPhone(), |
| | | currentJudge.getDescription() |
| | | ); |
| | | } |
| | | } |