feat: 作品管理分配状态/评委回显 + 评委管理租户隔离

Changes:
1. ContestWorkServiceImpl: findAll 返回 assignments、_count 数据 + assignStatus 搜索
2. ContestJudgeServiceImpl: 评委列表返回 assignedCount(已分配作品数)
3. JudgesManagementServiceImpl: 评委库租户隔离(查询当前租户+平台评委,创建在当前租户、平台评委只读)
4. judges/Index.vue: 增加"来源"列 + 平台评委操作限制
5. judges-management.ts: 类型增加 isPlatform/tenantId
6. WorksDetail.vue: 小修改

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
zhonghua 2026-04-07 17:10:40 +08:00
parent 3fd7002e2a
commit 170d904081
7 changed files with 270 additions and 75 deletions

View File

@ -18,12 +18,17 @@ import com.competition.modules.biz.contest.mapper.ContestRegistrationMapper;
import com.competition.modules.biz.contest.mapper.ContestWorkAttachmentMapper;
import com.competition.modules.biz.contest.mapper.ContestWorkMapper;
import com.competition.modules.biz.contest.service.IContestWorkService;
import com.competition.modules.biz.review.entity.BizContestWorkJudgeAssignment;
import com.competition.modules.biz.review.mapper.ContestWorkJudgeAssignmentMapper;
import com.competition.modules.sys.entity.SysUser;
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.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
@ -39,6 +44,8 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
private final ContestWorkAttachmentMapper contestWorkAttachmentMapper;
private final ContestRegistrationMapper contestRegistrationMapper;
private final ContestMapper contestMapper;
private final ContestWorkJudgeAssignmentMapper assignmentMapper;
private final SysUserMapper sysUserMapper;
@Override
@Transactional(rollbackFor = Exception.class)
@ -160,6 +167,57 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
} else if (!isSuperTenant && tenantId != null) {
wrapper.eq(BizContestWork::getTenantId, tenantId);
}
// username 筛选对应报名表的 account_no
if (StringUtils.hasText(dto.getUsername())) {
LambdaQueryWrapper<BizContestRegistration> userRegWrapper = new LambdaQueryWrapper<>();
if (dto.getContestId() != null) {
userRegWrapper.eq(BizContestRegistration::getContestId, dto.getContestId());
}
if (dto.getTenantId() != null) {
userRegWrapper.eq(BizContestRegistration::getTenantId, dto.getTenantId());
} else if (!isSuperTenant && tenantId != null) {
userRegWrapper.eq(BizContestRegistration::getTenantId, tenantId);
}
userRegWrapper.eq(BizContestRegistration::getValidState, 1);
userRegWrapper.like(BizContestRegistration::getAccountNo, dto.getUsername());
List<BizContestRegistration> userRegs = contestRegistrationMapper.selectList(userRegWrapper);
Set<Long> userRegIds = userRegs.stream()
.map(BizContestRegistration::getId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
if (!userRegIds.isEmpty()) {
wrapper.in(BizContestWork::getRegistrationId, userRegIds);
} else {
// 没有匹配的报名记录返回空结果
wrapper.eq(BizContestWork::getId, -1L);
}
}
// name 筛选对应报名表的 account_name
if (StringUtils.hasText(dto.getName())) {
LambdaQueryWrapper<BizContestRegistration> nameRegWrapper = new LambdaQueryWrapper<>();
if (dto.getContestId() != null) {
nameRegWrapper.eq(BizContestRegistration::getContestId, dto.getContestId());
}
if (dto.getTenantId() != null) {
nameRegWrapper.eq(BizContestRegistration::getTenantId, dto.getTenantId());
} else if (!isSuperTenant && tenantId != null) {
nameRegWrapper.eq(BizContestRegistration::getTenantId, tenantId);
}
nameRegWrapper.eq(BizContestRegistration::getValidState, 1);
nameRegWrapper.like(BizContestRegistration::getAccountName, dto.getName());
List<BizContestRegistration> nameRegs = contestRegistrationMapper.selectList(nameRegWrapper);
Set<Long> nameRegIds = nameRegs.stream()
.map(BizContestRegistration::getId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
if (!nameRegIds.isEmpty()) {
wrapper.in(BizContestWork::getRegistrationId, nameRegIds);
} else {
wrapper.eq(BizContestWork::getId, -1L);
}
}
Set<Long> keywordRegistrationIds = Collections.emptySet();
if (StringUtils.hasText(dto.getKeyword())) {
String keyword = dto.getKeyword();
@ -200,12 +258,34 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
}
}
if (StringUtils.hasText(dto.getSubmitStartTime())) {
wrapper.ge(BizContestWork::getSubmitTime,
LocalDateTime.parse(dto.getSubmitStartTime(), DateTimeFormatter.ISO_LOCAL_DATE_TIME));
wrapper.ge(BizContestWork::getSubmitTime, parseDateTime(dto.getSubmitStartTime(), true));
}
if (StringUtils.hasText(dto.getSubmitEndTime())) {
wrapper.le(BizContestWork::getSubmitTime,
LocalDateTime.parse(dto.getSubmitEndTime(), DateTimeFormatter.ISO_LOCAL_DATE_TIME));
wrapper.le(BizContestWork::getSubmitTime, parseDateTime(dto.getSubmitEndTime(), false));
}
// assignStatus 筛选基于分配表判断已分配/未分配
if (StringUtils.hasText(dto.getAssignStatus()) && dto.getContestId() != null) {
LambdaQueryWrapper<BizContestWorkJudgeAssignment> assignQueryWrapper = new LambdaQueryWrapper<>();
assignQueryWrapper.eq(BizContestWorkJudgeAssignment::getContestId, dto.getContestId());
assignQueryWrapper.select(BizContestWorkJudgeAssignment::getWorkId);
assignQueryWrapper.groupBy(BizContestWorkJudgeAssignment::getWorkId);
List<BizContestWorkJudgeAssignment> assignedRecords = assignmentMapper.selectList(assignQueryWrapper);
Set<Long> assignedWorkIds = assignedRecords.stream()
.map(BizContestWorkJudgeAssignment::getWorkId)
.collect(Collectors.toSet());
if ("assigned".equals(dto.getAssignStatus())) {
if (assignedWorkIds.isEmpty()) {
wrapper.eq(BizContestWork::getId, -1L);
} else {
wrapper.in(BizContestWork::getId, assignedWorkIds);
}
} else if ("unassigned".equals(dto.getAssignStatus())) {
if (!assignedWorkIds.isEmpty()) {
wrapper.notIn(BizContestWork::getId, assignedWorkIds);
}
}
}
// 默认只查最新版本
@ -241,8 +321,39 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
.collect(Collectors.toMap(BizContest::getId, c -> c));
}
// 批量查询分配信息
Set<Long> workIds = result.getRecords().stream()
.map(BizContestWork::getId)
.collect(Collectors.toSet());
Map<Long, List<BizContestWorkJudgeAssignment>> assignmentMap = new HashMap<>();
Map<Long, String> judgeNameMap = new HashMap<>();
if (!workIds.isEmpty()) {
LambdaQueryWrapper<BizContestWorkJudgeAssignment> assignWrapper = new LambdaQueryWrapper<>();
assignWrapper.in(BizContestWorkJudgeAssignment::getWorkId, workIds);
if (dto.getContestId() != null) {
assignWrapper.eq(BizContestWorkJudgeAssignment::getContestId, dto.getContestId());
}
List<BizContestWorkJudgeAssignment> allAssignments = assignmentMapper.selectList(assignWrapper);
assignmentMap = allAssignments.stream()
.collect(Collectors.groupingBy(BizContestWorkJudgeAssignment::getWorkId));
// 批量查询评委用户信息
Set<Long> judgeIds = allAssignments.stream()
.map(BizContestWorkJudgeAssignment::getJudgeId)
.collect(Collectors.toSet());
if (!judgeIds.isEmpty()) {
List<SysUser> judgeUsers = sysUserMapper.selectBatchIds(judgeIds);
for (SysUser u : judgeUsers) {
judgeNameMap.put(u.getId(), u.getNickname());
}
}
}
Map<Long, BizContestRegistration> finalRegistrationMap = registrationMap;
Map<Long, BizContest> finalContestMap = contestMap;
Map<Long, List<BizContestWorkJudgeAssignment>> finalAssignmentMap = assignmentMap;
Map<Long, String> finalJudgeNameMap = judgeNameMap;
List<Map<String, Object>> voList = result.getRecords().stream()
.map(work -> {
Map<String, Object> map = workToMap(work);
@ -279,6 +390,28 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
map.put("accountName", reg.getAccountName());
map.put("userId", reg.getUserId());
}
// 分配信息
List<BizContestWorkJudgeAssignment> workAssignments = finalAssignmentMap.getOrDefault(work.getId(), Collections.emptyList());
List<Map<String, Object>> assignmentVoList = workAssignments.stream().map(a -> {
Map<String, Object> assignVo = new LinkedHashMap<>();
assignVo.put("id", a.getId());
assignVo.put("judgeId", a.getJudgeId());
assignVo.put("status", a.getStatus());
assignVo.put("assignmentTime", a.getAssignmentTime());
Map<String, Object> judgeVo = new LinkedHashMap<>();
judgeVo.put("id", a.getJudgeId());
judgeVo.put("nickname", finalJudgeNameMap.getOrDefault(a.getJudgeId(), ""));
assignVo.put("judge", judgeVo);
return assignVo;
}).collect(Collectors.toList());
map.put("assignments", assignmentVoList);
// _count 用于分配状态判断
Map<String, Object> countVo = new LinkedHashMap<>();
countVo.put("assignments", workAssignments.size());
map.put("_count", countVo);
return map;
})
.collect(Collectors.toList());
@ -435,6 +568,18 @@ public class ContestWorkServiceImpl extends ServiceImpl<ContestWorkMapper, BizCo
// ====== 私有辅助方法 ======
/**
* 解析时间参数支持 "yyyy-MM-dd" "yyyy-MM-ddTHH:mm:ss" 两种格式
* isStart=true 时纯日期补 00:00:00isStart=false 时纯日期补 23:59:59
*/
private LocalDateTime parseDateTime(String value, boolean isStart) {
if (value.contains("T")) {
return LocalDateTime.parse(value, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}
LocalDate date = LocalDate.parse(value, DateTimeFormatter.ISO_LOCAL_DATE);
return isStart ? date.atStartOfDay() : date.atTime(23, 59, 59);
}
private String generateWorkNo(Long contestId) {
LambdaQueryWrapper<BizContestWork> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(BizContestWork::getContestId, contestId);

View File

@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.competition.common.enums.ErrorCode;
import com.competition.common.exception.BusinessException;
import com.competition.common.result.PageResult;
import com.competition.common.util.SecurityUtil;
import com.competition.modules.biz.judge.service.IJudgesManagementService;
import com.competition.modules.sys.entity.SysRole;
import com.competition.modules.sys.entity.SysTenant;
@ -48,23 +49,56 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
}
/**
* 获取评委角色 ID
* 获取或自动创建评委角色 ID
*/
private Long getJudgeRoleId(Long tenantId) {
private Long getOrCreateJudgeRoleId(Long tenantId) {
LambdaQueryWrapper<SysRole> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysRole::getCode, "judge");
wrapper.eq(SysRole::getTenantId, tenantId);
SysRole role = sysRoleMapper.selectOne(wrapper);
if (role == null) {
throw BusinessException.of(ErrorCode.BAD_REQUEST, "评委角色不存在,请先在评委租户下创建 code='judge' 的角色");
if (role != null) {
return role.getId();
}
// 自动创建 judge 角色
role = new SysRole();
role.setTenantId(tenantId);
role.setCode("judge");
role.setName("评委");
role.setDescription("评委角色");
sysRoleMapper.insert(role);
log.info("自动创建评委角色租户ID{}角色ID{}", tenantId, role.getId());
return role.getId();
}
/**
* 验证评委是否可被当前租户操作查看/编辑/删除
* 返回 true 表示是平台评委只读false 表示是本租户评委
*/
private boolean checkJudgeOwnership(SysUser user) {
Long currentTenantId = SecurityUtil.getCurrentTenantId();
Long judgeTenantId = getJudgeTenantId();
// 不属于当前租户也不属于平台评委租户
if (!currentTenantId.equals(user.getTenantId()) && !judgeTenantId.equals(user.getTenantId())) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
}
return judgeTenantId.equals(user.getTenantId());
}
/**
* 验证评委可被修改操作非平台评委 + 属于当前租户
*/
private void checkJudgeWritable(SysUser user) {
if (checkJudgeOwnership(user)) {
throw BusinessException.of(ErrorCode.FORBIDDEN, "平台评委不允许修改");
}
}
/**
* SysUser 转为前端需要的 Map
*/
private Map<String, Object> toMap(SysUser user) {
Long judgeTenantId = getJudgeTenantId();
Map<String, Object> map = new LinkedHashMap<>();
map.put("id", user.getId());
map.put("username", user.getUsername());
@ -77,6 +111,8 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
map.put("userSource", user.getUserSource());
map.put("createTime", user.getCreateTime());
map.put("modifyTime", user.getModifyTime());
map.put("tenantId", user.getTenantId());
map.put("isPlatform", judgeTenantId.equals(user.getTenantId()));
return map;
}
@ -97,19 +133,19 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
throw BusinessException.of(ErrorCode.BAD_REQUEST, "密码不能为空");
}
Long judgeTenantId = getJudgeTenantId();
Long currentTenantId = SecurityUtil.getCurrentTenantId();
// 检查用户名在评委租户内唯一
// 检查用户名在当前租户内唯一
LambdaQueryWrapper<SysUser> dupWrapper = new LambdaQueryWrapper<>();
dupWrapper.eq(SysUser::getTenantId, judgeTenantId);
dupWrapper.eq(SysUser::getTenantId, currentTenantId);
dupWrapper.eq(SysUser::getUsername, username);
if (sysUserMapper.selectCount(dupWrapper) > 0) {
throw BusinessException.of(ErrorCode.BAD_REQUEST, "该用户名已存在");
}
// 创建用户
// 创建用户归属当前租户
SysUser user = new SysUser();
user.setTenantId(judgeTenantId);
user.setTenantId(currentTenantId);
user.setUsername(username);
user.setPassword(passwordEncoder.encode(password));
user.setNickname(nickname);
@ -121,8 +157,8 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
user.setStatus("enabled");
sysUserMapper.insert(user);
// 分配评委角色
Long judgeRoleId = getJudgeRoleId(judgeTenantId);
// 分配评委角色在当前租户下查找或自动创建 judge 角色
Long judgeRoleId = getOrCreateJudgeRoleId(currentTenantId);
SysUserRole userRole = new SysUserRole();
userRole.setUserId(user.getId());
userRole.setRoleId(judgeRoleId);
@ -134,10 +170,12 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
@Override
public PageResult<Map<String, Object>> findAll(Long page, Long pageSize, String keyword, String status) {
Long currentTenantId = SecurityUtil.getCurrentTenantId();
Long judgeTenantId = getJudgeTenantId();
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(SysUser::getTenantId, judgeTenantId);
// 查询当前租户评委 + 平台评委
wrapper.in(SysUser::getTenantId, List.of(currentTenantId, judgeTenantId));
if (keyword != null && !keyword.isBlank()) {
wrapper.and(w -> w
@ -168,12 +206,7 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
if (user == null) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
}
Long judgeTenantId = getJudgeTenantId();
if (!judgeTenantId.equals(user.getTenantId())) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
}
checkJudgeOwnership(user);
return toMap(user);
}
@ -184,11 +217,7 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
if (user == null) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
}
Long judgeTenantId = getJudgeTenantId();
if (!judgeTenantId.equals(user.getTenantId())) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
}
checkJudgeWritable(user);
if (params.containsKey("nickname")) {
user.setNickname((String) params.get("nickname"));
@ -231,11 +260,7 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
if (user == null) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
}
Long judgeTenantId = getJudgeTenantId();
if (!judgeTenantId.equals(user.getTenantId())) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
}
checkJudgeWritable(user);
user.setStatus(status);
sysUserMapper.updateById(user);
@ -247,11 +272,7 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
if (user == null) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
}
Long judgeTenantId = getJudgeTenantId();
if (!judgeTenantId.equals(user.getTenantId())) {
throw BusinessException.of(ErrorCode.NOT_FOUND, "评委不存在");
}
checkJudgeWritable(user);
sysUserMapper.deleteById(id);
log.info("评委已删除ID{}", id);
@ -264,15 +285,15 @@ public class JudgesManagementServiceImpl implements IJudgesManagementService {
return;
}
Long judgeTenantId = getJudgeTenantId();
Long currentTenantId = SecurityUtil.getCurrentTenantId();
// 校验所有 ID 都属于评委租户
// 校验所有 ID 都属于当前租户不允许删除平台评委
LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
wrapper.in(SysUser::getId, ids);
wrapper.eq(SysUser::getTenantId, judgeTenantId);
wrapper.eq(SysUser::getTenantId, currentTenantId);
Long count = sysUserMapper.selectCount(wrapper);
if (count != ids.size()) {
throw BusinessException.of(ErrorCode.BAD_REQUEST, "部分评委不存在或不属于评委库");
throw BusinessException.of(ErrorCode.BAD_REQUEST, "部分评委不存在或不属于当前机构");
}
sysUserMapper.deleteBatchIds(ids);

View File

@ -5,7 +5,9 @@ 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.entity.BizContestJudge;
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.SysUser;
import com.competition.modules.sys.mapper.SysUserMapper;
@ -23,6 +25,7 @@ import java.util.stream.Collectors;
public class ContestJudgeServiceImpl extends ServiceImpl<ContestJudgeMapper, BizContestJudge> implements IContestJudgeService {
private final ContestJudgeMapper contestJudgeMapper;
private final ContestWorkJudgeAssignmentMapper assignmentMapper;
private final SysUserMapper sysUserMapper;
@Override
@ -71,6 +74,15 @@ public class ContestJudgeServiceImpl extends ServiceImpl<ContestJudgeMapper, Biz
}
}
// 批量查询每个评委在该赛事下的已分配作品数
Map<Long, Long> assignedCountMap = new HashMap<>();
for (BizContestJudge j : judges) {
LambdaQueryWrapper<BizContestWorkJudgeAssignment> assignWrapper = new LambdaQueryWrapper<>();
assignWrapper.eq(BizContestWorkJudgeAssignment::getContestId, contestId);
assignWrapper.eq(BizContestWorkJudgeAssignment::getJudgeId, j.getJudgeId());
assignedCountMap.put(j.getJudgeId(), assignmentMapper.selectCount(assignWrapper));
}
return judges.stream().map(j -> {
Map<String, Object> map = new LinkedHashMap<>();
map.put("id", j.getId());
@ -80,6 +92,7 @@ public class ContestJudgeServiceImpl extends ServiceImpl<ContestJudgeMapper, Biz
map.put("weight", j.getWeight());
map.put("description", j.getDescription());
map.put("createTime", j.getCreateTime());
map.put("assignedCount", assignedCountMap.getOrDefault(j.getJudgeId(), 0L));
SysUser user = userMap.get(j.getJudgeId());
if (user != null) {

View File

@ -16,6 +16,8 @@ export interface Judge {
modifier?: number;
createTime?: string;
modifyTime?: string;
tenantId?: number;
isPlatform?: boolean;
roles?: Array<{
id: number;
role: {

View File

@ -64,7 +64,7 @@
:loading="loading"
:pagination="pagination"
:row-selection="rowSelection"
row-key="id"
row-key="assignmentId"
@change="handleTableChange"
>
<template #bodyCell="{ column, record, index }">
@ -75,18 +75,18 @@
<a @click="handleViewWork(record)">{{ record.workNo || "-" }}</a>
</template>
<template v-else-if="column.key === 'score'">
<span v-if="record.score !== null" class="score">
{{ Number(record.score).toFixed(2) }}
<span v-if="record.totalScore != null" class="score">
{{ Number(record.totalScore).toFixed(2) }}
</span>
<span v-else class="text-gray">-</span>
</template>
<template v-else-if="column.key === 'reviewStatus'">
<a-tag v-if="record.reviewStatus === 'reviewed'" color="success">已评审</a-tag>
<a-tag v-if="record.status === 'completed'" color="success">已评审</a-tag>
<a-tag v-else color="default">未评审</a-tag>
</template>
<template v-else-if="column.key === 'action'">
<a-button type="link" size="small" @click="handleReview(record)">
{{ record.reviewStatus === 'reviewed' ? '查看' : '评审' }}
{{ record.status === 'completed' ? '查看' : '评审' }}
</a-button>
</template>
</template>
@ -169,7 +169,7 @@ const columns = [
{
title: "报名账号",
key: "accountNo",
dataIndex: "accountNo",
dataIndex: "submitterAccountNo",
width: 150,
},
{
@ -200,7 +200,7 @@ const currentWorkIndex = ref<number>(0)
const workListForNav = computed(() => {
return dataSource.value.map((item: any) => ({
workId: item.workId,
assignmentId: item.id,
assignmentId: item.assignmentId,
}))
})
@ -258,10 +258,10 @@ const handleViewWork = (record: any) => {
//
const handleReview = (record: any) => {
currentAssignmentId.value = record.id
currentAssignmentId.value = record.assignmentId
currentWorkId.value = record.workId
//
const index = dataSource.value.findIndex((item: any) => item.id === record.id)
const index = dataSource.value.findIndex((item: any) => item.assignmentId === record.assignmentId)
currentWorkIndex.value = index >= 0 ? index : 0
reviewModalVisible.value = true
}
@ -270,7 +270,7 @@ const handleReview = (record: any) => {
const handleNavigate = (index: number) => {
const item = dataSource.value[index]
if (item) {
currentAssignmentId.value = item.id
currentAssignmentId.value = item.assignmentId
currentWorkId.value = item.workId
currentWorkIndex.value = index
}

View File

@ -27,10 +27,10 @@
<a-popconfirm
v-permission="'judge:delete'"
title="确定要删除选中的评委吗?"
:disabled="selectedRowKeys.length === 0"
:disabled="selectedRowKeys.length === 0 || selectedRows.every(r => r.isPlatform)"
@confirm="handleBatchDelete"
>
<a-button danger :disabled="selectedRowKeys.length === 0">
<a-button danger :disabled="selectedRowKeys.length === 0 || selectedRows.every(r => r.isPlatform)">
<template #icon><DeleteOutlined /></template>
删除
</a-button>
@ -116,6 +116,10 @@
<span v-else-if="record.gender === 'female'"></span>
<span v-else>-</span>
</template>
<template v-else-if="column.key === 'source'">
<a-tag v-if="record.isPlatform" color="blue">平台</a-tag>
<span v-else>-</span>
</template>
<template v-else-if="column.key === 'status'">
<a-tag :color="record.status === 'enabled' ? 'success' : 'error'">
{{ record.status === "enabled" ? "启用" : "停用" }}
@ -140,23 +144,28 @@
</template>
<template v-else-if="column.key === 'action'">
<a-space>
<a-button
v-permission="'judge:update'"
type="link"
size="small"
@click="handleToggleStatus(record)"
>
{{ record.status === "enabled" ? "冻结" : "解冻" }}
</a-button>
<a-button
v-permission="'judge:update'"
type="link"
size="small"
@click="handleEdit(record)"
>
编辑
</a-button>
<template v-if="!record.isPlatform">
<a-button
v-permission="'judge:update'"
type="link"
size="small"
@click="handleToggleStatus(record)"
>
{{ record.status === "enabled" ? "冻结" : "解冻" }}
</a-button>
</template>
<template v-if="!record.isPlatform">
<a-button
v-permission="'judge:update'"
type="link"
size="small"
@click="handleEdit(record)"
>
编辑
</a-button>
</template>
<a-popconfirm
v-if="!record.isPlatform"
v-permission="'judge:delete'"
title="确定要删除这个评委吗?"
@confirm="handleDelete(record.id)"
@ -346,6 +355,11 @@ const columns = [
key: "index",
width: 70,
},
{
title: "来源",
key: "source",
width: 80,
},
{
title: "所属单位",
key: "organization",

View File

@ -255,16 +255,16 @@
>
<template #bodyCell="{ column, record }">
<template v-if="column.key === 'judgeName'">
{{ record.judge?.nickname || record.judge?.username || "-" }}
{{ record.judgeName || record.judgeUsername || "-" }}
</template>
<template v-else-if="column.key === 'phone'">
{{ record.judge?.phone || "-" }}
{{ record.phone || "-" }}
</template>
<template v-else-if="column.key === 'tenant'">
{{ record.judge?.organization || record.judge?.tenant?.name || "-" }}
{{ record.organization || record.tenantName || "-" }}
</template>
<template v-else-if="column.key === 'assignedCount'">
{{ record._count?.assignedContestWorks || 0 }}
{{ record.assignedCount || 0 }}
</template>
</template>
</a-table>
@ -283,10 +283,10 @@
<a-list-item>
<a-list-item-meta>
<template #title>
{{ item.judge?.nickname || item.judge?.username || "-" }}
{{ item.judgeName || item.judgeUsername || "-" }}
</template>
<template #description>
{{ item.judge?.organization || item.judge?.tenant?.name || "-" }}
{{ item.organization || item.tenantName || "-" }}
</template>
</a-list-item-meta>
<template #actions>