影像回退逻辑增加
continuous-integration/drone/push Build is passing

This commit is contained in:
2025-04-08 14:50:45 +08:00
parent 8213c6d10f
commit 4fd77ce70d
9 changed files with 19583 additions and 9 deletions
@@ -2552,6 +2552,7 @@ public class VisitTaskService(IRepository<VisitTask> _visitTaskRepository,
//回退后,回退状态恢复
sv.RequestBackState = RequestBackStateEnum.NotRequest;
sv.ImageBackState = ImageBackStateEnum.None;
sv.IsCheckBack = false;
sv.CheckBackTime = null;
sv.CheckState = CheckStateEnum.None;
@@ -2108,6 +2108,7 @@ namespace IRaCIS.Core.Application.Contracts
public DateTime? ReviewAuditTime { get; set; }
public DateTime? PreliminaryAuditTime { get; set; }
public ImageBackStateEnum ImageBackState { get; set; }
public DateTime? AuditTime => QCProcessEnum == TrialQCProcess.SingleAudit ? PreliminaryAuditTime : (QCProcessEnum == TrialQCProcess.DoubleAudit ? ReviewAuditTime : null);
}
@@ -3,6 +3,7 @@ using IRaCIS.Core.Application.Contracts.DTO;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Application.Helper;
using IRaCIS.Core.Application.Service.Inspection.DTO;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Infrastructure;
using Medallion.Threading;
@@ -38,6 +39,7 @@ namespace IRaCIS.Core.Application.Image.QA
IRepository<ReadingQuestionCriterionTrial> _readingQuestionCriterionTrialRepository,
IDistributedLockProvider _distributedLockProvider, IReadingClinicalDataService _readingClinicalDataService,
IOSSService _oSSService,
IRepository<ReadingClinicalData> _readingClinicalDataReposiotry,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IWebHostEnvironment _hostEnvironment) : BaseService, IQCOperationService
{
@@ -239,6 +241,132 @@ namespace IRaCIS.Core.Application.Image.QA
#endregion
#region CRC IQC 退
/// <summary>
/// CRC IQC 申请影像回退
/// </summary>
/// <param name="subjectVisitId"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[HttpPut]
public async Task<IResponseOutput> RequestImageBack(Guid subjectVisitId)
{
if (!_subjectVisitRepository.Any(t => t.Id == subjectVisitId && t.CheckState < CheckStateEnum.CVPassed && t.SubmitState == SubmitStateEnum.Submitted))
{
//一致性核查通过前已提交的影像才允许进行回退
throw new BusinessValidationFailedException(_localizer["QCOperation_ShouldBeforeCheckPassed"]);
}
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.ClinicalResearchCoordinator)
{
await _subjectVisitRepository.UpdatePartialFromQueryAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { ImageBackState = ImageBackStateEnum.CRCRequestBack }, true);
}
if (_userInfo.UserTypeEnumInt == (int)UserTypeEnum.IQC)
{
await _subjectVisitRepository.UpdatePartialFromQueryAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { ImageBackState = ImageBackStateEnum.IQCRequestBack }, true);
}
return ResponseOutput.Ok();
}
/// <summary>
/// PM 审核CRC IQC 申请影像回退
/// </summary>
/// <param name="subjectVisitId"></param>
/// <param name="isAgree"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[HttpPut]
public async Task<IResponseOutput> AuditImageBack(Guid subjectVisitId, bool isAgree)
{
var sv = (await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId)).IfNullThrowException();
if (sv.ImageBackState != ImageBackStateEnum.CRCRequestBack && sv.ImageBackState != ImageBackStateEnum.IQCRequestBack)
{
//当前访视状态不在影像回退状态,不允许审核通过
throw new BusinessValidationFailedException(_localizer["QCOperation_NotInRequestImageBackState"]);
}
if (isAgree)
{
if (sv.CheckState < CheckStateEnum.CVPassed)
{
//一致性核查通过前才允许进行回退
throw new BusinessValidationFailedException(_localizer["QCOperation_ShouldBeforeCheckPassed"]);
}
sv.ImageBackState = ImageBackStateEnum.PMAgreeBack;
#region 退
//需要重新产生任务
sv.IsVisitTaskGenerated = false;
sv.IsPMBackOrReReading = true;
sv.AuditState = AuditStateEnum.None;
sv.SubmitState = SubmitStateEnum.ToSubmit;
sv.ReadingStatus = ReadingStatusEnum.ImageNotSubmit;
//回退后,回退状态恢复
sv.RequestBackState = RequestBackStateEnum.NotRequest;
sv.IsCheckBack = false;
sv.CheckBackTime = null;
sv.CheckState = CheckStateEnum.None;
sv.CheckChallengeState = CheckChanllengeTypeEnum.None;
sv.SVENDTC = null;
sv.SVSTDTC = null;
sv.PreliminaryAuditTime = null;
sv.SubmitTime = null;
sv.ReviewAuditTime = null;
sv.CurrentActionUserExpireTime = null;
sv.IsTake = false;
sv.CurrentActionUserId = null;
sv.PreliminaryAuditUserId = null;
sv.ReviewAuditUserId = null;
if (sv.IsBaseLine)
{
await _readingClinicalDataReposiotry.UpdatePartialFromQueryAsync(t => t.ReadingId == sv.Id && (t.ClinicalDataTrialSet.ClinicalDataLevel == ClinicalLevel.Subject || t.ClinicalDataTrialSet.ClinicalDataLevel == ClinicalLevel.SubjectVisit), c => new ReadingClinicalData() { IsSign = false, ReadingClinicalDataState = ReadingClinicalDataStatus.HaveUploaded });
}
else
{
await _readingClinicalDataReposiotry.UpdatePartialFromQueryAsync(t => t.ReadingId == sv.Id && t.ClinicalDataTrialSet.ClinicalDataLevel == ClinicalLevel.SubjectVisit, c => new ReadingClinicalData()
{
IsSign = false,
ReadingClinicalDataState = ReadingClinicalDataStatus.HaveUploaded,
IsBlind = null,
IsComplete = null
});
}
await _trialQCQuestionAnswerRepository.BatchDeleteNoTrackingAsync(t => t.SubjectVisitId == subjectVisitId);
#endregion
}
else
{
sv.ImageBackState = ImageBackStateEnum.PMNotAgreeBack;
}
await _subjectVisitRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
#endregion
#region
/// <summary>
@@ -731,7 +859,7 @@ namespace IRaCIS.Core.Application.Image.QA
/// <returns></returns>
[HttpPut]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> SetNodicomStudyState(Guid subjectVisitId, Guid noneDicomStudyId, Guid? noneDicomStudyFileId, int state)
public async Task<IResponseOutput> SetNodicomStudyState(Guid subjectVisitId, Guid noneDicomStudyId, Guid? noneDicomStudyFileId, int state)
{
await VerifyIsCanQCAsync(null, subjectVisitId);
@@ -757,7 +885,7 @@ namespace IRaCIS.Core.Application.Image.QA
else if (state == 5)
{
noneDicomStudy.IsDeleted = false;
}
}
//设置检查下面的文件
@@ -1697,8 +1825,8 @@ namespace IRaCIS.Core.Application.Image.QA
//删除 软删除的物理文件
var instancePathList = await _dicomInstanceRepository.Where(t => (t.DicomSerie.IsDeleted || t.IsDeleted) && t.SubjectVisitId == subjectVisitId, false, true)
.Select(t => t.Path).ToListAsync();
var noneDicomFileList = await _noneDicomStudyFileRepository.Where(t => (t.NoneDicomStudy.IsDeleted ||t.IsDeleted) && t.NoneDicomStudy.SubjectVisitId == subjectVisitId, false, true)
.Select(t => t.Path).ToListAsync();
var noneDicomFileList = await _noneDicomStudyFileRepository.Where(t => (t.NoneDicomStudy.IsDeleted || t.IsDeleted) && t.NoneDicomStudy.SubjectVisitId == subjectVisitId, false, true)
.Select(t => t.Path).ToListAsync();
@@ -1739,13 +1867,13 @@ namespace IRaCIS.Core.Application.Image.QA
//删除影像
await _dicomStudyRepository.BatchDeleteNoTrackingAsync(t => t.IsDeleted && t.SubjectVisitId == subjectVisitId);
await _dicomSeriesRepository.BatchDeleteNoTrackingAsync(t => t.IsDeleted && t.SubjectVisitId == subjectVisitId);
await _dicomSeriesRepository.BatchDeleteNoTrackingAsync(t => t.IsDeleted && t.SubjectVisitId == subjectVisitId);
await _dicomInstanceRepository.BatchDeleteNoTrackingAsync(t => (t.DicomSerie.IsDeleted || t.IsDeleted) && t.SubjectVisitId == subjectVisitId);
await _noneDicomStudyFileRepository.BatchDeleteNoTrackingAsync(t => (t.NoneDicomStudy.IsDeleted || t.IsDeleted) && t.NoneDicomStudy.SubjectVisitId == subjectVisitId);
await _noneDicomStudyRepository.BatchDeleteNoTrackingAsync(t => t.IsDeleted && t.SubjectVisitId == subjectVisitId);
await _noneDicomStudyRepository.BatchDeleteNoTrackingAsync(t => t.IsDeleted && t.SubjectVisitId == subjectVisitId);
await _oSSService.DeleteObjects(instancePathList.Select(t => t.TrimStart('/')).ToList());
await _oSSService.DeleteObjects(noneDicomFileList.Select(t => t.TrimStart('/')).ToList());
}