QC 审核提交--迁移uat
continuous-integration/drone/push Build is passing Details

Uat_IRC_Net8
hang 2025-07-15 10:12:09 +08:00
parent c556061a79
commit 574629970c
14 changed files with 132 additions and 10 deletions

View File

@ -1118,7 +1118,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
HtmlPath = k.HtmlPath,
Path = k.Path,
InstanceNumber = k.InstanceNumber,
FileSize=k.FileSize,
}).ToList()
})
});

View File

@ -270,6 +270,7 @@ namespace IRaCIS.Core.Application.Contracts.DTO
public QARelationInfo RelationInfo { get; set; } = new QARelationInfo();
public List<DateTime?> SecondReviewTimeList { get; set; }
}

View File

@ -2013,6 +2013,8 @@ namespace IRaCIS.Core.Application.Contracts
// 1代表第一个人QC数据 2 代表第二个人QC数据
public CurrentQC CurrentQCEnum { get; set; }
public DateTime? SecondReviewTime { get; set; }
}
public class ForwardQuery : PageInput
@ -2167,6 +2169,7 @@ namespace IRaCIS.Core.Application.Contracts
public class QCVisitBasicListViewModel
{
public SecondReviewState SecondReviewState { get; set; }
public bool IsSubjectQuit { get; set; }
public ChallengeStateEnum ChallengeState { get; set; }
public bool? IsConfirmedClinicalData { get; set; }

View File

@ -35,6 +35,8 @@ namespace IRaCIS.Core.Application.Contracts
public DateTime UpdateTime { get; set; }
public Guid UpdateUserId { get; set; }
public bool IsQuestionQCAuditPassed { get; set; }
}
public class QCQuestionFilterSelect

View File

@ -7,6 +7,7 @@ using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Infrastructure.Extention;
using MassTransit.Initializers;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
namespace IRaCIS.Core.Application.Image.QA
{
@ -411,10 +412,28 @@ namespace IRaCIS.Core.Application.Image.QA
var qacheckList = await GetQCQuestionAnswerList(subjectVisitId, sv.TrialId, trialQCProcess, currentQCType);
List<DateTime?> secondReviewTimeList = new List<DateTime?>();
if (sv.SecondReviewState != SecondReviewState.None)
{
secondReviewTimeList = _trialQCQuestionAnswerRepository.Where(t => t.SubjectVisitId == subjectVisitId && t.CurrentQCEnum == CurrentQC.SecondReview).Where(t => t.SecondReviewTime != null)
.Select(t => t.SecondReviewTime).Distinct().ToList();
var trialConfirmTime = _trialRepository.Where(t => t.Id == sv.TrialId).Select(t => t.QCQuestionConfirmedTime).FirstOrDefault();
if (!secondReviewTimeList.Contains(trialConfirmTime))
{
secondReviewTimeList.Add(trialConfirmTime);
}
}
return new TrialVisitQADTO
{
QCQuestionAnswerList = qacheckList,
SecondReviewTimeList = secondReviewTimeList,
IsHaveStudyClinicalData = await _clinicalDataTrialSetRepository.AnyAsync(x => x.IsConfirm && x.TrialId == sv.TrialId && x.ClinicalDataLevel == ClinicalLevel.Study),
StudyList = temp.StudyList,
ExistsManual = (await _IReadingImageTaskService.GetManualList(new GetManualListInDto() { TrialId = sv.TrialId })).Count() > 0,
@ -434,8 +453,45 @@ namespace IRaCIS.Core.Application.Image.QA
[HttpPost]
public async Task<List<QCQuestionAnswer>> GetQCQuestionAnswer(GetQCQuestionAnswerInDto inDto)
{
var questionAnswerlist = await (from data in _trialQCQuestionRepository.Where(x => x.TrialId == inDto.TrialId && x.IsEnable)
join answer in _trialQCQuestionAnswerRepository.Where(x => x.SubjectVisitId == inDto.SubjectVisitId && x.QCProcessEnum == inDto.QCProcessEnum && x.CurrentQCEnum == inDto.CurrentQCEnum).AsQueryable() on data.Id equals answer.TrialQCQuestionConfigureId into answertemp
var subjectVisitId = inDto.SubjectVisitId;
List<QCQuestionAnswer> questionAnswerlist = new List<QCQuestionAnswer>();
//判断当前访视质控是否完成,再判断复审是完成查看,还是添加编辑
var sv = await _subjectVisitRepository.Where(t => t.Id == subjectVisitId).FirstNotNullAsync();
if (sv.SecondReviewState == SecondReviewState.None && sv.AuditState == AuditStateEnum.QCPassed)
{
//现在之前历史质控的展示要从答案为主表取数据,添加和编辑按照之前方式
questionAnswerlist = await _trialQCQuestionAnswerRepository.Where(x => x.SubjectVisitId == inDto.SubjectVisitId && x.QCProcessEnum == inDto.QCProcessEnum && x.CurrentQCEnum == inDto.CurrentQCEnum)
.Select(data => new QCQuestionAnswer()
{
Answer = data.Answer,
ShowOrder = data.TrialQCQuestionConfigure.ShowOrder,
QuestionName = data.TrialQCQuestionConfigure.QuestionName,
Id = data.TrialQCQuestionConfigure.Id,
IsRequired = data.TrialQCQuestionConfigure.IsRequired,
ParentId = data.TrialQCQuestionConfigure.ParentId,
ParentTriggerValue = data.TrialQCQuestionConfigure.ParentTriggerValue,
Type = data.TrialQCQuestionConfigure.Type,
TypeValue = data.TrialQCQuestionConfigure.TypeValue
}).OrderBy(t => t.ShowOrder).ToListAsync();
}
else
{
var secondReviewTime = inDto.SecondReviewTime != null ? (DateTime)inDto.SecondReviewTime : DateTime.Now;
#region 之前编辑和审核通过后展示都是通过这个接口
questionAnswerlist = await (from data in _trialQCQuestionRepository.Where(x => x.TrialId == inDto.TrialId && x.IsEnable)
join answer in _trialQCQuestionAnswerRepository.Where(x => x.SubjectVisitId == inDto.SubjectVisitId && x.QCProcessEnum == inDto.QCProcessEnum && x.CurrentQCEnum == inDto.CurrentQCEnum)
.Where(t => inDto.CurrentQCEnum == CurrentQC.SecondReview ? t.SecondReviewTime >= secondReviewTime && t.SecondReviewTime <= secondReviewTime.AddSeconds(1) : true)
on data.Id equals answer.TrialQCQuestionConfigureId into answertemp
from leftanswer in answertemp.DefaultIfEmpty()
select new QCQuestionAnswer()
{
@ -449,6 +505,17 @@ namespace IRaCIS.Core.Application.Image.QA
Type = data.Type,
TypeValue = data.TypeValue
}).OrderBy(t => t.ShowOrder).ToListAsync();
#endregion
}
var result = questionAnswerlist.Where(x => x.ParentId == null).OrderBy(t => t.ShowOrder).ToList();
result.ForEach(x =>

View File

@ -730,6 +730,8 @@ namespace IRaCIS.Core.Application.Image.QA
//验证是否能操作
await VerifyIsCanQCAsync(null, subjectVisitId);
var trialConfirmTime = _trialRepository.Where(t => t.Id == trialId).Select(t => t.QCQuestionConfirmedTime).FirstOrDefault();
//更新
if (qcQuestionAnswerCommands.Any(t => t.Id != null))
{
@ -774,7 +776,9 @@ namespace IRaCIS.Core.Application.Image.QA
{
var addlist = _mapper.Map<List<TrialQCQuestionAnswer>>(qcQuestionAnswerCommands);
addlist.ForEach(t => { t.TrialId = trialId; t.SubjectVisitId = subjectVisitId; t.CurrentQCEnum = currentQCType; t.QCProcessEnum = trialQCProcess; });
addlist.ForEach(t => { t.TrialId = trialId; t.SubjectVisitId = subjectVisitId; t.CurrentQCEnum = currentQCType; t.QCProcessEnum = trialQCProcess; t.SecondReviewTime = currentQCType == CurrentQC.SecondReview ? trialConfirmTime : null; });
await _trialQCQuestionAnswerRepository.AddRangeAsync(addlist);

View File

@ -479,6 +479,7 @@ namespace IRaCIS.Core.Application.Service
CreateMap<TrialQCQuestion, TrialQCQuestionAddOrEdit>();
CreateMap<TrialQCQuestion, TrialQCQuestionConfigureView>()
.ForMember(d => d.IsQuestionQCAuditPassed, u => u.MapFrom(s => s.TrialQCQuestionAnswerList.Any(c => c.TrialQCQuestionConfigureId == s.Id && c.SubjectVisit.AuditState == AuditStateEnum.QCPassed)))
.ForMember(d => d.ParentShowOrder, u => u.MapFrom(s => s.ParentQCQuestion.ShowOrder));
CreateMap<TrialQCQuestionSelect, TrialQCQuestionConfigureView>();

View File

@ -41,6 +41,7 @@ namespace IRaCIS.Core.Application
IRepository<SystemBasicData> _systemBasicDataRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<Enroll> _enrollRepository,
IRepository<TrialQCQuestionAnswer> _qcQuestionAnswerRepository,
IRepository<TrialStateChange> _trialStateChangeRepository,
IRepository<ReadingTableQuestionTrial> _readingTableQuestionTrialRepository, IRepository<TrialDicomAE> _dicomAERepository,
IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer, IFusionCache _fusionCache) : BaseService, ITrialConfigService
@ -861,9 +862,18 @@ namespace IRaCIS.Core.Application
{
await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { IsTrialUrgentConfirmed = true });
}
else
else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialQCQuestionConfirmUpdate).ToString())
{
await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { QCQuestionConfirmedTime = null, QCQuestionConfirmedUserId = null, IsQCQuestionConfirmed = false });
}
else if (signConfirmDTO.SignCode == ((int)SignEnum.SecondReviewConfirm).ToString())
{
await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.Id == signConfirmDTO.TrialId && t.AuditState == AuditStateEnum.QCPassed, u => new SubjectVisit() { SecondReviewState = SecondReviewState.WaitAudit });
if (signConfirmDTO.SignCode == ((int)SignEnum.TrialQCQuestionConfirm).ToString())
//删除复审中间临时数据
await _qcQuestionAnswerRepository.BatchDeleteNoTrackingAsync(t => t.SubjectVisit.TrialId == signConfirmDTO.TrialId && t.SubjectVisit.AuditState != AuditStateEnum.QCPassed && t.CurrentQCEnum == CurrentQC.SecondReview);
}
else if (signConfirmDTO.SignCode == ((int)SignEnum.TrialQCQuestionConfirm).ToString())
{
var trialConfig = (await _trialRepository
@ -909,9 +919,9 @@ namespace IRaCIS.Core.Application
IsConfirm = true
});
await _trialRepository.UpdatePartialFromQueryAsync(t => t.Id == signConfirmDTO.TrialId, u => new Trial() { QCQuestionConfirmedTime = DateTime.Now, QCQuestionConfirmedUserId = _userInfo.UserRoleId, IsQCQuestionConfirmed = true });
await _trialRepository.SaveChangesAsync();
}
await _trialRepository.SaveChangesAsync();
return ResponseOutput.Ok();

View File

@ -29,6 +29,13 @@ namespace IRaCIS.Core.Domain.Share
TrialQCQuestionConfirm=107,
//重置质控问题配置
TrialQCQuestionConfirmUpdate=112,
SecondReviewConfirm = 219,
}
}

View File

@ -19,4 +19,14 @@ namespace IRaCIS.Core.Domain.Share
}
public enum SecondReviewState
{
None = 0,
WaitAudit=1,
AuditPassed=2,
AuditFailed=3,
}
}

View File

@ -14,7 +14,11 @@
First = 1,
Second = 2
Second = 2,
//二次复核,只会一个人
SecondReview=3,
}

View File

@ -8,6 +8,9 @@ public class TrialQCQuestionAnswer : BaseFullAuditEntity
#region 导航属性
[JsonIgnore]
public TrialQCQuestion TrialQCQuestionConfigure { get; set; }
[JsonIgnore]
public SubjectVisit SubjectVisit { get; set; }
#endregion
public Guid TrialId { get; set; }
@ -20,4 +23,7 @@ public class TrialQCQuestionAnswer : BaseFullAuditEntity
public Guid SubjectVisitId { get; set; }
public Guid TrialQCQuestionConfigureId { get; set; }
public DateTime? SecondReviewTime { get; set; }
}

View File

@ -75,7 +75,7 @@ public class SubjectVisit : BaseFullDeleteAuditEntity
public List<SubjectCriteriaEvaluationVisitFilter> SubjectCriteriaEvaluationVisitFilterList { get; set; }
[JsonIgnore]
public List<SubjectVisitImageBackRecord> SubjectVisitImageBackRecordList { get; set; }
public List<SubjectVisitImageBackRecord> SubjectVisitImageBackRecordList { get; set; }
#endregion
public Guid TrialSiteId { get; set; }
@ -188,7 +188,7 @@ public class SubjectVisit : BaseFullDeleteAuditEntity
public Guid? SubmitUserId { get; set; }
public ReadingStatusEnum ReadingStatus { get; set; }
public SecondReviewState SecondReviewState { get; set; }
}
[Comment("受试者访视影像回退记录表")]

View File

@ -217,6 +217,13 @@ namespace IRaCIS.Core.Infra.EFCore.Common
extraIdentification = oldentity.IsConfigureEmail ? "/EmailUpdate" : "/EmailSave";
break;
case "configTrialBasicInfo/TrialConfigSignatureConfirm":
if (entity.IsQCQuestionConfirmed == false)
{
extraIdentification = $"/ConfirmReset";
}
break;
}
//var trialDicomAE = await _dbContext.TrialDicomAE.Where(t => t.TrialId == entity.Id).FirstOrDefaultAsync();