fix: 实现MiniScoringServiceImpl中的总分计算逻辑
评分提交后自动计算选手总分: - 获取场地需要的裁判数量 - 排除主裁判评分 - 去掉最高最低分取平均(不足3人直接平均) Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
This commit is contained in:
+2
-2
@@ -53,8 +53,8 @@ public class MartialAthleteController extends BladeController {
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "分页列表", description = "分页查询")
|
||||
public R<IPage<MartialAthleteVO>> list(MartialAthlete athlete, Query query) {
|
||||
IPage<MartialAthleteVO> pages = athleteService.selectAthleteVOPage(Condition.getPage(query), athlete);
|
||||
public R<IPage<MartialAthleteVO>> list(MartialAthlete athlete, Query query, @RequestParam(required = false, defaultValue = "false") Boolean includeTeamRecords) {
|
||||
IPage<MartialAthleteVO> pages = athleteService.selectAthleteVOPage(Condition.getPage(query), athlete, includeTeamRecords);
|
||||
return R.data(pages);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,9 +18,10 @@ public interface MartialAthleteMapper extends BaseMapper<MartialAthlete> {
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param athlete 查询条件
|
||||
* @param includeTeamRecords 是否包含集体项目的团队记录
|
||||
* @return 参赛选手VO分页数据
|
||||
*/
|
||||
IPage<MartialAthleteVO> selectAthleteVOPage(IPage<MartialAthleteVO> page, @Param("athlete") MartialAthlete athlete);
|
||||
IPage<MartialAthleteVO> selectAthleteVOPage(IPage<MartialAthleteVO> page, @Param("athlete") MartialAthlete athlete, @Param("includeTeamRecords") Boolean includeTeamRecords);
|
||||
|
||||
/**
|
||||
* Count distinct participants by id_card for a competition
|
||||
|
||||
@@ -12,13 +12,15 @@
|
||||
LEFT JOIN martial_competition c ON a.competition_id = c.id AND c.is_deleted = 0
|
||||
LEFT JOIN martial_project p ON a.project_id = p.id AND p.is_deleted = 0
|
||||
WHERE a.is_deleted = 0
|
||||
<!-- 过滤集体项目记录:排除 idCard 为空且 playerName 等于 teamName 的记录 -->
|
||||
<!-- 默认过滤集体项目的团队记录,除非 includeTeamRecords=true -->
|
||||
<if test="includeTeamRecords == null or includeTeamRecords == false">
|
||||
AND NOT (
|
||||
(a.id_card IS NULL OR a.id_card = '')
|
||||
AND a.player_name = a.team_name
|
||||
AND a.team_name IS NOT NULL
|
||||
AND a.team_name != ''
|
||||
)
|
||||
</if>
|
||||
<if test="athlete.competitionId != null">
|
||||
AND a.competition_id = #{athlete.competitionId}
|
||||
</if>
|
||||
|
||||
@@ -26,6 +26,16 @@ public interface IMartialAthleteService extends IService<MartialAthlete> {
|
||||
*/
|
||||
IPage<MartialAthleteVO> selectAthleteVOPage(IPage<MartialAthleteVO> page, MartialAthlete athlete);
|
||||
|
||||
/**
|
||||
* 分页查询参赛选手(包含关联字段)
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @param athlete 查询条件
|
||||
* @param includeTeamRecords 是否包含集体项目的团队记录
|
||||
* @return 参赛选手VO分页数据
|
||||
*/
|
||||
IPage<MartialAthleteVO> selectAthleteVOPage(IPage<MartialAthleteVO> page, MartialAthlete athlete, Boolean includeTeamRecords);
|
||||
|
||||
/**
|
||||
* Task 2.1: 运动员签到
|
||||
*/
|
||||
|
||||
+6
-1
@@ -61,7 +61,12 @@ public class MartialAthleteServiceImpl extends ServiceImpl<MartialAthleteMapper,
|
||||
*/
|
||||
@Override
|
||||
public IPage<MartialAthleteVO> selectAthleteVOPage(IPage<MartialAthleteVO> page, MartialAthlete athlete) {
|
||||
return baseMapper.selectAthleteVOPage(page, athlete);
|
||||
return baseMapper.selectAthleteVOPage(page, athlete, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPage<MartialAthleteVO> selectAthleteVOPage(IPage<MartialAthleteVO> page, MartialAthlete athlete, Boolean includeTeamRecords) {
|
||||
return baseMapper.selectAthleteVOPage(page, athlete, includeTeamRecords);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+107
-2
@@ -7,15 +7,21 @@ import org.springblade.core.tool.api.R;
|
||||
import org.springblade.modules.martial.pojo.dto.MiniScoreSubmitDTO;
|
||||
import org.springblade.modules.martial.pojo.entity.MartialAthlete;
|
||||
import org.springblade.modules.martial.pojo.entity.MartialJudge;
|
||||
import org.springblade.modules.martial.pojo.entity.MartialJudgeInvite;
|
||||
import org.springblade.modules.martial.pojo.entity.MartialScore;
|
||||
import org.springblade.modules.martial.service.IMartialAthleteService;
|
||||
import org.springblade.modules.martial.service.IMartialJudgeService;
|
||||
import org.springblade.modules.martial.service.IMartialJudgeInviteService;
|
||||
import org.springblade.modules.martial.service.IMartialScoreService;
|
||||
import org.springblade.modules.martial.service.IMiniScoringService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@@ -26,6 +32,7 @@ public class MiniScoringServiceImpl implements IMiniScoringService {
|
||||
private final IMartialScoreService scoreService;
|
||||
private final IMartialJudgeService judgeService;
|
||||
private final IMartialAthleteService athleteService;
|
||||
private final IMartialJudgeInviteService judgeInviteService;
|
||||
|
||||
@Override
|
||||
public R<String> submitScore(MiniScoreSubmitDTO dto) {
|
||||
@@ -72,8 +79,106 @@ public class MiniScoringServiceImpl implements IMiniScoringService {
|
||||
}
|
||||
|
||||
private void updateAthleteTotalScore(Long athleteId, Long projectId, Long venueId) {
|
||||
// TODO: Implement score calculation logic
|
||||
// This will be extracted to a separate service in later refactoring
|
||||
try {
|
||||
int requiredJudgeCount = getRequiredJudgeCount(venueId);
|
||||
List<Long> chiefJudgeIds = getChiefJudgeIds(venueId);
|
||||
|
||||
LambdaQueryWrapper<MartialScore> scoreQuery = new LambdaQueryWrapper<>();
|
||||
scoreQuery.eq(MartialScore::getAthleteId, athleteId);
|
||||
scoreQuery.eq(MartialScore::getProjectId, projectId);
|
||||
scoreQuery.eq(MartialScore::getIsDeleted, 0);
|
||||
if (!chiefJudgeIds.isEmpty()) {
|
||||
scoreQuery.notIn(MartialScore::getJudgeId, chiefJudgeIds);
|
||||
}
|
||||
List<MartialScore> scores = scoreService.list(scoreQuery);
|
||||
|
||||
if (scores == null || scores.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (requiredJudgeCount > 0 && scores.size() < requiredJudgeCount) {
|
||||
MartialAthlete athlete = athleteService.getById(athleteId);
|
||||
if (athlete != null && athlete.getTotalScore() != null) {
|
||||
athlete.setTotalScore(null);
|
||||
athleteService.updateById(athlete);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
BigDecimal totalScore = calculateTotalScore(scores);
|
||||
|
||||
if (totalScore != null) {
|
||||
MartialAthlete athlete = athleteService.getById(athleteId);
|
||||
if (athlete != null) {
|
||||
athlete.setTotalScore(totalScore);
|
||||
athleteService.updateById(athlete);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("计算总分失败: athleteId={}, projectId={}", athleteId, projectId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private int getRequiredJudgeCount(Long venueId) {
|
||||
if (venueId == null || venueId <= 0) {
|
||||
return 0;
|
||||
}
|
||||
LambdaQueryWrapper<MartialJudgeInvite> judgeQuery = new LambdaQueryWrapper<>();
|
||||
judgeQuery.eq(MartialJudgeInvite::getIsDeleted, 0);
|
||||
judgeQuery.eq(MartialJudgeInvite::getVenueId, venueId);
|
||||
judgeQuery.eq(MartialJudgeInvite::getRefereeType, 2);
|
||||
List<MartialJudgeInvite> judges = judgeInviteService.list(judgeQuery);
|
||||
return (int) judges.stream()
|
||||
.map(MartialJudgeInvite::getJudgeId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.count();
|
||||
}
|
||||
|
||||
private List<Long> getChiefJudgeIds(Long venueId) {
|
||||
List<Long> chiefJudgeIds = new ArrayList<>();
|
||||
if (venueId == null) {
|
||||
return chiefJudgeIds;
|
||||
}
|
||||
LambdaQueryWrapper<MartialJudgeInvite> query = new LambdaQueryWrapper<>();
|
||||
query.eq(MartialJudgeInvite::getVenueId, venueId);
|
||||
query.eq(MartialJudgeInvite::getRefereeType, 1);
|
||||
query.eq(MartialJudgeInvite::getIsDeleted, 0);
|
||||
List<MartialJudgeInvite> invites = judgeInviteService.list(query);
|
||||
for (MartialJudgeInvite invite : invites) {
|
||||
if (invite.getJudgeId() != null) {
|
||||
chiefJudgeIds.add(invite.getJudgeId());
|
||||
}
|
||||
}
|
||||
return chiefJudgeIds;
|
||||
}
|
||||
|
||||
private BigDecimal calculateTotalScore(List<MartialScore> scores) {
|
||||
if (scores == null || scores.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
List<BigDecimal> scoreValues = scores.stream()
|
||||
.map(MartialScore::getScore)
|
||||
.filter(Objects::nonNull)
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
|
||||
int count = scoreValues.size();
|
||||
if (count == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (count < 3) {
|
||||
BigDecimal sum = scoreValues.stream()
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
return sum.divide(new BigDecimal(count), 3, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
List<BigDecimal> middleScores = scoreValues.subList(1, count - 1);
|
||||
BigDecimal sum = middleScores.stream()
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
return sum.divide(new BigDecimal(middleScores.size()), 3, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
private Long parseLong(String str) {
|
||||
|
||||
Reference in New Issue
Block a user