From 7d7ef9820b7aff5792c03cd53194ef51da3409f9 Mon Sep 17 00:00:00 2001 From: zhonghua Date: Wed, 8 Apr 2026 11:30:54 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BD=9C=E5=93=81=E5=88=86=E9=85=8D?= =?UTF-8?q?=E8=AF=84=E5=A7=94=E7=A7=BB=E9=99=A4=E5=90=8E=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=BA=93=E5=B9=B6=E5=85=81=E8=AE=B8=E6=B8=85?= =?UTF-8?q?=E7=A9=BA=E8=AF=84=E5=A7=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Made-with: Cursor --- .../impl/ContestReviewServiceImpl.java | 37 +++++++++++++++++-- .../src/views/contests/works/WorksDetail.vue | 9 ++--- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/ContestReviewServiceImpl.java b/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/ContestReviewServiceImpl.java index ba4a227..fe600f8 100644 --- a/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/ContestReviewServiceImpl.java +++ b/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/ContestReviewServiceImpl.java @@ -26,6 +26,7 @@ import com.competition.modules.sys.mapper.SysUserMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.util.StringUtils; import java.math.BigDecimal; @@ -51,13 +52,42 @@ public class ContestReviewServiceImpl implements IContestReviewService { // ====== 作品分配 ====== @Override + @Transactional(rollbackFor = Exception.class) public Map assignWork(Long contestId, Long workId, List judgeIds, Long creatorId) { - log.info("分配作品,赛事ID:{},作品ID:{},评委数:{}", contestId, workId, judgeIds.size()); + if (judgeIds == null) { + judgeIds = Collections.emptyList(); + } + // 去重后保持顺序,作为本次期望的评委集合 + List desiredOrder = new ArrayList<>(new LinkedHashSet<>(judgeIds)); + Set desired = new HashSet<>(desiredOrder); + + log.info("分配作品(同步),赛事ID:{},作品ID:{},期望评委数:{}", contestId, workId, desired.size()); + + // 1. 取消已分配但不在本次列表中的评委(仅删除未评分的分配行) + LambdaQueryWrapper existWrapper = new LambdaQueryWrapper<>(); + existWrapper.eq(BizContestWorkJudgeAssignment::getContestId, contestId); + existWrapper.eq(BizContestWorkJudgeAssignment::getWorkId, workId); + List existing = assignmentMapper.selectList(existWrapper); + + int removed = 0; + for (BizContestWorkJudgeAssignment a : existing) { + if (desired.contains(a.getJudgeId())) { + continue; + } + LambdaQueryWrapper scoreWrapper = new LambdaQueryWrapper<>(); + scoreWrapper.eq(BizContestWorkScore::getAssignmentId, a.getId()); + scoreWrapper.eq(BizContestWorkScore::getValidState, 1); + if (scoreMapper.selectCount(scoreWrapper) > 0) { + throw BusinessException.of(ErrorCode.BAD_REQUEST, "部分评委已提交评分,无法取消其分配,请先处理评分记录"); + } + assignmentMapper.deleteById(a.getId()); + removed++; + } int created = 0; int skipped = 0; - for (Long judgeId : judgeIds) { + for (Long judgeId : desiredOrder) { // 检查是否已分配 LambdaQueryWrapper dupWrapper = new LambdaQueryWrapper<>(); dupWrapper.eq(BizContestWorkJudgeAssignment::getContestId, contestId); @@ -81,10 +111,11 @@ public class ContestReviewServiceImpl implements IContestReviewService { created++; } - log.info("作品分配完成,新建:{},跳过:{}", created, skipped); + log.info("作品分配完成,移除:{},新建:{},跳过(已存在):{}", removed, created, skipped); Map result = new LinkedHashMap<>(); result.put("workId", workId); + result.put("removed", removed); result.put("created", created); result.put("skipped", skipped); return result; diff --git a/frontend/src/views/contests/works/WorksDetail.vue b/frontend/src/views/contests/works/WorksDetail.vue index a2ba400..caa5b2f 100644 --- a/frontend/src/views/contests/works/WorksDetail.vue +++ b/frontend/src/views/contests/works/WorksDetail.vue @@ -227,8 +227,7 @@