package com.labelsys.backend.service; import java.util.List; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.labelsys.backend.common.ResultCode; import com.labelsys.backend.common.exception.BusinessException; import com.labelsys.backend.context.LoginUser; import com.labelsys.backend.dto.common.PageResult; import com.labelsys.backend.dto.request.AnnotationResultPageQuery; import com.labelsys.backend.dto.response.AnnotationResultCompareResponse; import com.labelsys.backend.dto.response.AnnotationResultResponse; import com.labelsys.backend.entity.AnnotationResult; import com.labelsys.backend.entity.SourceResource; import com.labelsys.backend.enums.RuntimeResultStatus; import com.labelsys.backend.mapper.AnnotationResultMapper; import com.labelsys.backend.mapper.SourceResourceMapper; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @Slf4j @Service @RequiredArgsConstructor public class AnnotationResultService { private final AnnotationResultMapper annotationResultMapper; private final SourceResourceMapper sourceResourceMapper; private final DataPermissionService dataPermissionService; public PageResult pageResults(LoginUser currentUser, AnnotationResultPageQuery query) { List allowedRoles = dataPermissionService.getAllowedRoles(currentUser); boolean shouldFilterByUserId = dataPermissionService.shouldFilterByUserId(currentUser); LambdaQueryWrapper wrapper = new LambdaQueryWrapper().eq(AnnotationResult::getCompanyId, currentUser.companyId()) .eq(query.taskId() != null, AnnotationResult::getTaskId, query.taskId()) .eq(query.resourceId() != null, AnnotationResult::getResourceId, query.resourceId()) .eq(query.requiresManualReview() != null, AnnotationResult::getRequiresManualReview, query.requiresManualReview()); if (shouldFilterByUserId) { wrapper.eq(AnnotationResult::getCreatorId, currentUser.userId()); } else if (!allowedRoles.isEmpty()) { wrapper.in(AnnotationResult::getCreatorRole, allowedRoles); } wrapper.orderByDesc(AnnotationResult::getCreatedAt); Page page = new Page<>(query.pageNo(), query.pageSize()); Page resultPage = annotationResultMapper.selectPage(page, wrapper); List records = resultPage.getRecords().stream().map(this::toResponse) .filter(response -> query.runtimeStatus() == null || query.runtimeStatus().equals(response.runtimeStatus())) .toList(); return new PageResult<>(records, resultPage.getTotal(), (int)resultPage.getCurrent(), (int)resultPage.getSize()); } public AnnotationResultResponse getResult(LoginUser currentUser, Long resultId) { AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId, currentUser.companyId()); if (result == null) { log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}", resultId, currentUser.companyId(), currentUser.userId()); throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在"); } return toResponse(result); } public AnnotationResultCompareResponse compareResult(LoginUser currentUser, Long resultId) { AnnotationResult result = annotationResultMapper.findActiveByIdAndCompanyId(resultId, currentUser.companyId()); if (result == null) { log.warn("Result not found or cross-tenant access attempt: resultId={}, companyId={}, userId={}", resultId, currentUser.companyId(), currentUser.userId()); throw new BusinessException(ResultCode.NOT_FOUND, "结果不存在"); } SourceResource resource = sourceResourceMapper.selectById(result.getResourceId()); return new AnnotationResultCompareResponse(result.getId(), result.getTaskId(), result.getResourceId(), result.getQaContentJson(), result.getDiffSummary(), result.getQaContentStorageMode(), result.getQaContentFilePath(), resource == null ? null : resource.getFilePath()); } private AnnotationResultResponse toResponse(AnnotationResult result) { return new AnnotationResultResponse(result.getId(), result.getTaskId(), result.getResourceId(), deriveStatus(result), result.getRequiresManualReview(), result.getIsDeleted(), result.getQaContentStorageMode(), result.getReviewComment(), result.getReviewedAt(), result.getCreatedAt()); } private String deriveStatus(AnnotationResult result) { if (Boolean.TRUE.equals(result.getIsDeleted())) { return RuntimeResultStatus.ARCHIVED.name(); } if (Boolean.TRUE.equals(result.getRequiresManualReview())) { return RuntimeResultStatus.MANUAL_REVIEW_PENDING.name(); } return RuntimeResultStatus.AUTO_ARCHIVE_PENDING.name(); } }