From 7a039e8403e4b5a79b619d9b7e52d4ea5768d8ba Mon Sep 17 00:00:00 2001 From: zhonghua Date: Tue, 7 Apr 2026 19:16:13 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=E5=88=86=E9=85=8D=E8=AF=84=E5=A7=94?= =?UTF-8?q?=E6=97=B6=E5=BA=94=E8=AF=A5=E6=9F=A5=E8=AF=A2=E7=A7=9F=E6=88=B7?= =?UTF-8?q?=E4=B8=8B=E7=9A=84+=E5=B9=B3=E5=8F=B0=E7=9A=84=E8=AF=84?= =?UTF-8?q?=E5=A7=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../impl/JudgesManagementServiceImpl.java | 31 ++++++- .../controller/PresetCommentController.java | 13 ++- .../biz/review/dto/SyncPresetCommentsDto.java | 21 +++++ .../service/impl/ContestJudgeServiceImpl.java | 90 +++++++++++++++++-- .../impl/PresetCommentServiceImpl.java | 17 +++- 5 files changed, 150 insertions(+), 22 deletions(-) create mode 100644 backend-java/src/main/java/com/competition/modules/biz/review/dto/SyncPresetCommentsDto.java diff --git a/backend-java/src/main/java/com/competition/modules/biz/judge/service/impl/JudgesManagementServiceImpl.java b/backend-java/src/main/java/com/competition/modules/biz/judge/service/impl/JudgesManagementServiceImpl.java index 576b9dd..bd813bc 100644 --- a/backend-java/src/main/java/com/competition/modules/biz/judge/service/impl/JudgesManagementServiceImpl.java +++ b/backend-java/src/main/java/com/competition/modules/biz/judge/service/impl/JudgesManagementServiceImpl.java @@ -173,8 +173,37 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService { Long currentTenantId = SecurityUtil.getCurrentTenantId(); Long judgeTenantId = getJudgeTenantId(); + // 查询当前租户和平台评委租户的 judge 角色 ID + Set judgeRoleIds = new HashSet<>(); + for (Long tid : List.of(currentTenantId, judgeTenantId)) { + if (tid == null) continue; + LambdaQueryWrapper roleWrapper = new LambdaQueryWrapper<>(); + roleWrapper.eq(SysRole::getCode, "judge"); + roleWrapper.eq(SysRole::getTenantId, tid); + SysRole role = sysRoleMapper.selectOne(roleWrapper); + if (role != null) { + judgeRoleIds.add(role.getId()); + } + } + + // 查询拥有 judge 角色的用户 ID + Set judgeUserIds = new HashSet<>(); + if (!judgeRoleIds.isEmpty()) { + LambdaQueryWrapper urWrapper = new LambdaQueryWrapper<>(); + urWrapper.in(SysUserRole::getRoleId, judgeRoleIds); + List userRoles = sysUserRoleMapper.selectList(urWrapper); + for (SysUserRole ur : userRoles) { + judgeUserIds.add(ur.getUserId()); + } + } + + if (judgeUserIds.isEmpty()) { + return new PageResult<>(Collections.emptyList(), 0L, page, pageSize); + } + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); - // 查询当前租户评委 + 平台评委 + // 只查询拥有 judge 角色且属于当前租户或平台评委租户的用户 + wrapper.in(SysUser::getId, judgeUserIds); wrapper.in(SysUser::getTenantId, List.of(currentTenantId, judgeTenantId)); if (keyword != null && !keyword.isBlank()) { diff --git a/backend-java/src/main/java/com/competition/modules/biz/review/controller/PresetCommentController.java b/backend-java/src/main/java/com/competition/modules/biz/review/controller/PresetCommentController.java index 63a550d..00d1e8e 100644 --- a/backend-java/src/main/java/com/competition/modules/biz/review/controller/PresetCommentController.java +++ b/backend-java/src/main/java/com/competition/modules/biz/review/controller/PresetCommentController.java @@ -3,6 +3,7 @@ package com.competition.modules.biz.review.controller; import com.competition.common.result.Result; import com.competition.common.util.SecurityUtil; import com.competition.modules.biz.review.dto.CreatePresetCommentDto; +import com.competition.modules.biz.review.dto.SyncPresetCommentsDto; import com.competition.modules.biz.review.entity.BizPresetComment; import com.competition.modules.biz.review.service.IPresetCommentService; import io.swagger.v3.oas.annotations.Operation; @@ -65,11 +66,10 @@ public class PresetCommentController { return Result.success(); } - @SuppressWarnings("unchecked") @PostMapping("/batch-delete") @Operation(summary = "批量删除预设评语") - public Result batchDelete(@RequestBody Map body) { - List ids = (List) body.get("ids"); + public Result batchDelete(@RequestBody Map> body) { + List ids = body.get("ids"); Long judgeId = SecurityUtil.getCurrentUserId(); presetCommentService.batchDelete(ids, judgeId); return Result.success(); @@ -77,12 +77,9 @@ public class PresetCommentController { @PostMapping("/sync") @Operation(summary = "同步评语到其他赛事") - public Result> syncComments(@RequestBody Map body) { - Long sourceContestId = Long.valueOf(body.get("sourceContestId").toString()); - @SuppressWarnings("unchecked") - List targetContestIds = (List) body.get("targetContestIds"); + public Result> syncComments(@Valid @RequestBody SyncPresetCommentsDto dto) { Long judgeId = SecurityUtil.getCurrentUserId(); - return Result.success(presetCommentService.syncComments(sourceContestId, targetContestIds, judgeId)); + return Result.success(presetCommentService.syncComments(dto.getSourceContestId(), dto.getTargetContestIds(), judgeId)); } @PostMapping("/{id}/use") diff --git a/backend-java/src/main/java/com/competition/modules/biz/review/dto/SyncPresetCommentsDto.java b/backend-java/src/main/java/com/competition/modules/biz/review/dto/SyncPresetCommentsDto.java new file mode 100644 index 0000000..f4973db --- /dev/null +++ b/backend-java/src/main/java/com/competition/modules/biz/review/dto/SyncPresetCommentsDto.java @@ -0,0 +1,21 @@ +package com.competition.modules.biz.review.dto; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.util.List; + +@Data +@Schema(description = "同步预设评语DTO") +public class SyncPresetCommentsDto { + + @NotNull(message = "源赛事ID不能为空") + @Schema(description = "源赛事ID") + private Long sourceContestId; + + @NotEmpty(message = "目标赛事列表不能为空") + @Schema(description = "目标赛事ID列表") + private List targetContestIds; +} diff --git a/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/ContestJudgeServiceImpl.java b/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/ContestJudgeServiceImpl.java index 5a76f76..4e2a63b 100644 --- a/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/ContestJudgeServiceImpl.java +++ b/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/ContestJudgeServiceImpl.java @@ -9,7 +9,9 @@ import com.competition.modules.biz.review.entity.BizContestWorkJudgeAssignment; import com.competition.modules.biz.review.mapper.ContestJudgeMapper; import com.competition.modules.biz.review.mapper.ContestWorkJudgeAssignmentMapper; import com.competition.modules.biz.review.service.IContestJudgeService; +import com.competition.modules.sys.entity.SysTenant; import com.competition.modules.sys.entity.SysUser; +import com.competition.modules.sys.mapper.SysTenantMapper; import com.competition.modules.sys.mapper.SysUserMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -27,6 +29,7 @@ public class ContestJudgeServiceImpl extends ServiceImpl> findByContest(Long contestId) { log.info("查询赛事评委列表,赛事ID:{}", contestId); + // 获取平台评委租户 ID + Long judgeTenantId = getJudgeTenantId(); + + // 1. 查询已显式分配的评委 LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); wrapper.eq(BizContestJudge::getContestId, contestId); wrapper.eq(BizContestJudge::getValidState, 1); @@ -64,11 +71,32 @@ public class ContestJudgeServiceImpl extends ServiceImpl judges = contestJudgeMapper.selectList(wrapper); + // 收集所有需要查询的用户 ID(已分配评委) + Set assignedJudgeIds = judges.stream().map(BizContestJudge::getJudgeId).collect(Collectors.toSet()); + + // 2. 查询平台评委(自动对所有赛事可用) + List platformJudges = new ArrayList<>(); + if (judgeTenantId != null) { + LambdaQueryWrapper platformWrapper = new LambdaQueryWrapper<>(); + platformWrapper.eq(SysUser::getTenantId, judgeTenantId); + platformWrapper.eq(SysUser::getStatus, "enabled"); + platformJudges = sysUserMapper.selectList(platformWrapper); + } + + // 平台评委中去掉已显式分配的(避免重复) + Set platformOnlyIds = platformJudges.stream() + .map(SysUser::getId) + .filter(id -> !assignedJudgeIds.contains(id)) + .collect(Collectors.toSet()); + + // 合并所有需要查询的用户 ID + Set allUserIds = new HashSet<>(assignedJudgeIds); + allUserIds.addAll(platformOnlyIds); + // 批量查询用户信息 - Set userIds = judges.stream().map(BizContestJudge::getJudgeId).collect(Collectors.toSet()); Map userMap = new HashMap<>(); - if (!userIds.isEmpty()) { - List users = sysUserMapper.selectBatchIds(userIds); + if (!allUserIds.isEmpty()) { + List users = sysUserMapper.selectBatchIds(allUserIds); for (SysUser user : users) { userMap.put(user.getId(), user); } @@ -76,14 +104,17 @@ public class ContestJudgeServiceImpl extends ServiceImpl assignedCountMap = new HashMap<>(); - for (BizContestJudge j : judges) { + for (Long judgeId : allUserIds) { LambdaQueryWrapper assignWrapper = new LambdaQueryWrapper<>(); assignWrapper.eq(BizContestWorkJudgeAssignment::getContestId, contestId); - assignWrapper.eq(BizContestWorkJudgeAssignment::getJudgeId, j.getJudgeId()); - assignedCountMap.put(j.getJudgeId(), assignmentMapper.selectCount(assignWrapper)); + assignWrapper.eq(BizContestWorkJudgeAssignment::getJudgeId, judgeId); + assignedCountMap.put(judgeId, assignmentMapper.selectCount(assignWrapper)); } - return judges.stream().map(j -> { + List> result = new ArrayList<>(); + + // 构建已显式分配的评委数据 + for (BizContestJudge j : judges) { Map map = new LinkedHashMap<>(); map.put("id", j.getId()); map.put("contestId", j.getContestId()); @@ -98,9 +129,50 @@ public class ContestJudgeServiceImpl extends ServiceImpl map = new LinkedHashMap<>(); + map.put("id", null); + map.put("contestId", contestId); + map.put("judgeId", platformJudge.getId()); + map.put("specialty", null); + map.put("weight", null); + map.put("description", null); + map.put("createTime", null); + map.put("assignedCount", assignedCountMap.getOrDefault(platformJudge.getId(), 0L)); + map.put("judgeName", platformJudge.getNickname()); + map.put("judgeUsername", platformJudge.getUsername()); + map.put("tenantId", platformJudge.getTenantId()); + map.put("status", platformJudge.getStatus()); + map.put("organization", platformJudge.getOrganization()); + map.put("isPlatform", true); + result.add(map); + } + + return result; + } + + /** + * 获取平台评委租户 ID + */ + private Long getJudgeTenantId() { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + wrapper.eq(SysTenant::getCode, "judge"); + SysTenant tenant = sysTenantMapper.selectOne(wrapper); + return tenant != null ? tenant.getId() : null; } @Override diff --git a/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/PresetCommentServiceImpl.java b/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/PresetCommentServiceImpl.java index bd26dde..528bd1b 100644 --- a/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/PresetCommentServiceImpl.java +++ b/backend-java/src/main/java/com/competition/modules/biz/review/service/impl/PresetCommentServiceImpl.java @@ -6,6 +6,8 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.competition.common.enums.ErrorCode; import com.competition.common.exception.BusinessException; import com.competition.modules.biz.review.dto.CreatePresetCommentDto; +import com.competition.modules.biz.contest.entity.BizContest; +import com.competition.modules.biz.contest.mapper.ContestMapper; import com.competition.modules.biz.review.entity.BizContestJudge; import com.competition.modules.biz.review.entity.BizPresetComment; import com.competition.modules.biz.review.mapper.ContestJudgeMapper; @@ -25,6 +27,7 @@ public class PresetCommentServiceImpl extends ServiceImpl { Map map = new LinkedHashMap<>(); - map.put("contestId", j.getContestId()); + map.put("id", j.getContestId()); + // 查询赛事详情获取名称和状态 + BizContest contest = contestMapper.selectById(j.getContestId()); + if (contest != null) { + map.put("contestName", contest.getContestName()); + map.put("contestState", contest.getContestState()); + map.put("status", contest.getStatus()); + } return map; }).collect(Collectors.toList()); } @@ -201,9 +211,8 @@ public class PresetCommentServiceImpl extends ServiceImpl result = new LinkedHashMap<>(); - result.put("sourceCount", sourceComments.size()); - result.put("targetContests", targetContestIds.size()); - result.put("createdCount", created); + result.put("message", "同步成功"); + result.put("count", created); return result; } From 2f84ac16d31a22b7a3cfbbb76080c3b0deb314a9 Mon Sep 17 00:00:00 2001 From: zhonghua Date: Tue, 7 Apr 2026 19:32:44 +0800 Subject: [PATCH 2/2] =?UTF-8?q?fix:=E6=B7=BB=E5=8A=A0=E8=AF=84=E5=A7=94?= =?UTF-8?q?=E9=80=89=E6=8B=A9=E5=9B=9E=E6=98=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/views/contests/works/WorksDetail.vue | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/frontend/src/views/contests/works/WorksDetail.vue b/frontend/src/views/contests/works/WorksDetail.vue index 2a61658..9c54b74 100644 --- a/frontend/src/views/contests/works/WorksDetail.vue +++ b/frontend/src/views/contests/works/WorksDetail.vue @@ -607,13 +607,23 @@ const handleViewWork = (record: ContestWork) => { } // 单个分配评委 -const handleAssignJudge = (record: ContestWork) => { +const handleAssignJudge = async (record: ContestWork) => { currentAssignWork.value = record isBatchAssign.value = false selectedJudgeKeys.value = [] selectedJudgeRows.value = [] assignModalVisible.value = true - fetchJudgeList() + await fetchJudgeList() + + // 回显已分配的评委 + if (record.assignments && record.assignments.length > 0) { + const assignedJudgeUserIds = record.assignments.map((a) => a.judgeId) + const matchedJudges = judgeList.value.filter((judge) => + assignedJudgeUserIds.includes(judge.judgeId) + ) + selectedJudgeKeys.value = matchedJudges.map((j) => j.id) + selectedJudgeRows.value = matchedJudges + } } // 批量分配评委