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")
|
@GetMapping("/list")
|
||||||
@Operation(summary = "分页列表", description = "分页查询")
|
@Operation(summary = "分页列表", description = "分页查询")
|
||||||
public R<IPage<MartialAthleteVO>> list(MartialAthlete athlete, Query query) {
|
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);
|
IPage<MartialAthleteVO> pages = athleteService.selectAthleteVOPage(Condition.getPage(query), athlete, includeTeamRecords);
|
||||||
return R.data(pages);
|
return R.data(pages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,9 +18,10 @@ public interface MartialAthleteMapper extends BaseMapper<MartialAthlete> {
|
|||||||
*
|
*
|
||||||
* @param page 分页对象
|
* @param page 分页对象
|
||||||
* @param athlete 查询条件
|
* @param athlete 查询条件
|
||||||
|
* @param includeTeamRecords 是否包含集体项目的团队记录
|
||||||
* @return 参赛选手VO分页数据
|
* @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
|
* 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_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
|
LEFT JOIN martial_project p ON a.project_id = p.id AND p.is_deleted = 0
|
||||||
WHERE a.is_deleted = 0
|
WHERE a.is_deleted = 0
|
||||||
<!-- 过滤集体项目记录:排除 idCard 为空且 playerName 等于 teamName 的记录 -->
|
<!-- 默认过滤集体项目的团队记录,除非 includeTeamRecords=true -->
|
||||||
AND NOT (
|
<if test="includeTeamRecords == null or includeTeamRecords == false">
|
||||||
(a.id_card IS NULL OR a.id_card = '')
|
AND NOT (
|
||||||
AND a.player_name = a.team_name
|
(a.id_card IS NULL OR a.id_card = '')
|
||||||
AND a.team_name IS NOT NULL
|
AND a.player_name = a.team_name
|
||||||
AND a.team_name != ''
|
AND a.team_name IS NOT NULL
|
||||||
)
|
AND a.team_name != ''
|
||||||
|
)
|
||||||
|
</if>
|
||||||
<if test="athlete.competitionId != null">
|
<if test="athlete.competitionId != null">
|
||||||
AND a.competition_id = #{athlete.competitionId}
|
AND a.competition_id = #{athlete.competitionId}
|
||||||
</if>
|
</if>
|
||||||
|
|||||||
@@ -26,6 +26,16 @@ public interface IMartialAthleteService extends IService<MartialAthlete> {
|
|||||||
*/
|
*/
|
||||||
IPage<MartialAthleteVO> selectAthleteVOPage(IPage<MartialAthleteVO> page, MartialAthlete athlete);
|
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: 运动员签到
|
* Task 2.1: 运动员签到
|
||||||
*/
|
*/
|
||||||
|
|||||||
+6
-1
@@ -61,7 +61,12 @@ public class MartialAthleteServiceImpl extends ServiceImpl<MartialAthleteMapper,
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public IPage<MartialAthleteVO> selectAthleteVOPage(IPage<MartialAthleteVO> page, MartialAthlete athlete) {
|
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.dto.MiniScoreSubmitDTO;
|
||||||
import org.springblade.modules.martial.pojo.entity.MartialAthlete;
|
import org.springblade.modules.martial.pojo.entity.MartialAthlete;
|
||||||
import org.springblade.modules.martial.pojo.entity.MartialJudge;
|
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.pojo.entity.MartialScore;
|
||||||
import org.springblade.modules.martial.service.IMartialAthleteService;
|
import org.springblade.modules.martial.service.IMartialAthleteService;
|
||||||
import org.springblade.modules.martial.service.IMartialJudgeService;
|
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.IMartialScoreService;
|
||||||
import org.springblade.modules.martial.service.IMiniScoringService;
|
import org.springblade.modules.martial.service.IMiniScoringService;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@@ -26,6 +32,7 @@ public class MiniScoringServiceImpl implements IMiniScoringService {
|
|||||||
private final IMartialScoreService scoreService;
|
private final IMartialScoreService scoreService;
|
||||||
private final IMartialJudgeService judgeService;
|
private final IMartialJudgeService judgeService;
|
||||||
private final IMartialAthleteService athleteService;
|
private final IMartialAthleteService athleteService;
|
||||||
|
private final IMartialJudgeInviteService judgeInviteService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public R<String> submitScore(MiniScoreSubmitDTO dto) {
|
public R<String> submitScore(MiniScoreSubmitDTO dto) {
|
||||||
@@ -72,8 +79,106 @@ public class MiniScoringServiceImpl implements IMiniScoringService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateAthleteTotalScore(Long athleteId, Long projectId, Long venueId) {
|
private void updateAthleteTotalScore(Long athleteId, Long projectId, Long venueId) {
|
||||||
// TODO: Implement score calculation logic
|
try {
|
||||||
// This will be extracted to a separate service in later refactoring
|
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) {
|
private Long parseLong(String str) {
|
||||||
|
|||||||
Reference in New Issue
Block a user