irc-netcore-api/IRaCIS.Core.Application/Service/Visit/SubjectVisitService.cs

305 lines
13 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using IRaCIS.Core.Infrastructure.ExpressionExtend;
using IRaCIS.Core.Application.Filter;
using Microsoft.AspNetCore.Mvc;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using Microsoft.AspNetCore.Authorization;
using IRaCIS.Core.Domain.Share;
using IRaCIS.Core.Application.Contracts;
using IRaCIS.Core.Application.Interfaces;
using IRaCIS.Core.Application.Service.Inspection.Interface;
using Newtonsoft.Json;
namespace IRaCIS.Core.Application.Services
{
[ApiExplorerSettings(GroupName = "Trial")]
public class SubjectVisitService : BaseService, ISubjectVisitService
{
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly IInspectionService _inspectionService;
private readonly IRepository<Subject> _subjectRepository;
public SubjectVisitService(IRepository<SubjectVisit> subjectVisitRepository, IInspectionService inspectionService,IRepository<Subject> subjectRepository)
{
_subjectVisitRepository = subjectVisitRepository;
this._inspectionService = inspectionService;
_subjectRepository = subjectRepository;
}
[HttpPost]
[TypeFilter(typeof(TrialResourceFilter))]
[UnitOfWork]
public async Task<IResponseOutput<string>> AddOrUpdateSV(SubjectVisitCommand svCommand)
{
bool isadd=false;
if (svCommand.Id == null)
{
isadd=true;
}
var verifyExp1 = new EntityVerifyExp<SubjectVisit>()
{
VerifyExp = t => t.VisitNum == svCommand.VisitNum && t.SubjectId == svCommand.SubjectId,
VerifyMsg = "This subject's visit plan already contains a visit with the same visitnum."
};
var verifyExp2 = new EntityVerifyExp<SubjectVisit>()
{
VerifyExp = t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit,
VerifyMsg = "该受试者已经有访视设置为末次访视,不允许将该访视设置为末次访视",
IsVerify=svCommand.IsFinalVisit
};
svCommand.BlindName = "B" + ((int)(svCommand.VisitNum * 10)).ToString("D3");
var subject = (await _subjectRepository.FirstOrDefaultAsync(t => t.Id == svCommand.SubjectId)).IfNullThrowException();
svCommand.VisitExecuted = svCommand.IsLostVisit ? VisitExecutedEnum.Executed : svCommand.VisitExecuted;
//设置末次评估后,不允许添加计划外访视
if (svCommand.InPlan == false && svCommand.Id == null)
{
if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.IsFinalVisit))
{
return ResponseOutput.NotOk("设置末次评估后,不允许添加计划外访视");
}
}
//更新的时候,返回的是数据库此时的实体数据
var needDealEntity = await _subjectVisitRepository.InsertOrUpdateAsync(svCommand, false, verifyExp1, verifyExp2);
if (svCommand.PDState != needDealEntity.PDState && svCommand.Id != null && needDealEntity.SubmitState == SubmitStateEnum.Submitted)
{
return ResponseOutput.NotOk("CRC提交后不允许修改PD确认状态");
}
if (svCommand.PDState != needDealEntity.PDState && svCommand.Id != null && needDealEntity.RequestBackState == RequestBackStateEnum.PM_AgressBack)
{
return ResponseOutput.NotOk("回退的访视不允许修改PD确认状态");
}
if (svCommand.IsFinalVisit)
{
if (await _subjectVisitRepository.AnyAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitNum > svCommand.VisitNum && t.SubmitState == SubmitStateEnum.ToSubmit))
{
return ResponseOutput.NotOk("该受试者此访视后有影像上传,该访视不允许设置为末次访视");
}
subject.Status = SubjectStatus.OutOfVisit;
//末次访视后的 访视设置为不可用
await _subjectVisitRepository.BatchUpdateAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitNum > svCommand.VisitNum, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Unavailable });
}
else
{
//回退
subject.Status = SubjectStatus.OnVisit;
await _subjectVisitRepository.BatchUpdateAsync(t => t.SubjectId == svCommand.SubjectId && t.VisitExecuted == VisitExecutedEnum.Unavailable, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.UnExecuted });
}
if (svCommand.IsLostVisit && svCommand.Id == null)
{
if (await _subjectVisitRepository.AnyAsync(t => t.Id==svCommand.Id && t.SubmitState == SubmitStateEnum.ToSubmit))
{
return ResponseOutput.NotOk("该受试者此访视有影像上传,不允许设置为失访");
}
}
//更新受试者 首次给药日期 是否入组确认
if (svCommand.SubjectFirstGiveMedicineTime != null)
{
if (svCommand.IsBaseLine)
{
List<DataInspection> datas = new List<DataInspection>();
// 更新受试者
subject.FirstGiveMedicineTime = svCommand.SubjectFirstGiveMedicineTime;
datas.Add(new DataInspection()
{
SubjectId = subject.Id,
SiteId = subject.SiteId,
TrialId = subject.TrialId,
IsSign = false,
Identification = "Edit|Subject|Info|Subject",
CreateTime = DateTime.Now.AddSeconds(1),
JsonDetail = JsonConvert.SerializeObject(new
{
FirstGiveMedicineTime = subject.FirstGiveMedicineTime.Value.ToString("yyyy-MM-dd")
})
});
await _inspectionService.AddListInspectionRecordAsync(datas);
}
}
if (svCommand.IsEnrollmentConfirm != null)
{
await _subjectVisitRepository.BatchUpdateAsync(t => t.SubjectId == svCommand.SubjectId && t.IsBaseLine , u => new SubjectVisit() { IsEnrollmentConfirm = svCommand.IsEnrollmentConfirm.Value });
//needDealEntity.IsUrgent = true;
}
await _repository.SaveChangesAsync();
if (isadd)
{
List<DataInspection> dataInspection=new List<DataInspection>();
dataInspection.Add(new DataInspection()
{
TrialId = svCommand.TrialId,
SiteId = svCommand.SiteId,
SubjectId = svCommand.SubjectId,
SubjectVisitId = svCommand.Id,
SubjectVisitName = svCommand.VisitName,
IsSign = false,
CreateTime = DateTime.Now.AddSeconds(1),
Identification = "Init|Visit|Status|Visit-Image Upload",
JsonDetail = JsonConvert.SerializeObject(new
{
VisitName = svCommand.VisitName,
SubmitState = "",
AuditState = "",
})
});
await _inspectionService.AddListInspectionRecordAsync(dataInspection);
}
// 保存数据后,重新算下是否缺失影像 应对状态撤回
//if (svCommand.IsLostVisit == false)
//{
// var currentSubmittedVisitNum = await _repository.Where<SubjectVisit>(t => t.SubmitState == SubmitStateEnum.Submitted).MaxAsync(t => t.VisitNum);
// var isMissing = await _repository.AnyAsync<SubjectVisit>(t => (t.VisitNum < currentSubmittedVisitNum && t.SubmitState != SubmitStateEnum.Submitted) || t.IsLostVisit);
// await _repository.UpdateFromQueryAsync<Subject>(t => t.Id == svCommand.SubjectId, u => new Subject()
// {
// IsMissingImages = isMissing
// });
//}
return ResponseOutput.Ok(needDealEntity.Id.ToString());
}
[HttpPut("{trialId:guid}/{subjectVisitId:guid}/{isUrgent:bool}")]
public async Task<IResponseOutput> SetSubjectVisitUrgent(Guid subjectVisitId, bool isUrgent)
{
await _subjectVisitRepository.BatchUpdateAsync(t => t.Id == subjectVisitId, u => new SubjectVisit() { IsUrgent = isUrgent });
return ResponseOutput.Ok();
}
[HttpDelete, Route("{id:guid}/{trialId:guid}")]
[TrialAudit(AuditType.SubjectAudit, AuditOptType.DeleteSubjectOutPlanVisit)]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> DeleteSV(Guid id)
{
if (await _repository.AnyAsync<DicomStudy>(t => t.SubjectVisitId == id))
{
return ResponseOutput.NotOk("This visit is associated with the uploaded study images and couldn't be deleted.");
}
if (await _subjectVisitRepository.AnyAsync(t => t.Id == id && t.InPlan))
{
return ResponseOutput.NotOk("This visit is InPlan and couldn't be deleted.");
}
if (await _subjectVisitRepository.AnyAsync(t => t.OutPlanPreviousVisitId == id ))
{
return ResponseOutput.NotOk("This visit is OutPlanPreviousVisitId and couldn't be deleted.");
}
return ResponseOutput.Result(await _repository.BatchDeleteAsync<SubjectVisit>(s => s.Id == id));
}
/// <summary>
/// 设置受试者访视已执行 也就是将studyUploaded状态置为true 为了那些没有影像 人工设置准备
/// </summary>
/// <param name="subjectVisitId"></param>
/// <returns></returns>
[HttpPost("{subjectVisitId:guid}/{trialId:guid}")]
[TrialAudit(AuditType.SubjectAudit, AuditOptType.SetSVExecuted)]
[TypeFilter(typeof(TrialResourceFilter))]
public async Task<IResponseOutput> SetSVExecuted(Guid subjectVisitId)
{
return ResponseOutput.Result(await _subjectVisitRepository.BatchUpdateAsync(s => s.Id == subjectVisitId, u => new SubjectVisit() { VisitExecuted = VisitExecutedEnum.Executed }));
}
/// <summary>
/// 获取访视下的Dicom 检查信息 分所有的, 阅片的 不阅片 isReading : 0 查询所有 1 查询仅仅阅片的
/// </summary>
/// <param name="trialId"></param>
/// <param name="sujectVisitId"></param>
/// <param name="isReading"></param>
/// <returns></returns>
[HttpGet, Route("{trialId:guid}/{sujectVisitId:guid}/{isReading}")]
[AllowAnonymous]
public async Task<List<VisitStudyDTO>> GetVisitStudyList(Guid trialId, Guid sujectVisitId, int isReading)
{
var studyList = await _repository.Where<DicomStudy>(t => t.TrialId == trialId && t.SubjectVisitId == sujectVisitId).Select(k => new VisitStudyDTO()
{
InstanceCount = k.InstanceCount,
Modalities = k.Modalities,
SeriesCount = k.SeriesCount,
StudyCode = k.StudyCode,
StudyId = k.Id
}).ToListAsync();
var studyIds = studyList.Select(t => t.StudyId).ToList();
var instanceList = await _repository.Where<DicomInstance>(t => studyIds.Contains(t.StudyId))
.Select(t => new { t.SeriesId, t.Id, t.InstanceNumber }).ToListAsync();
foreach (var t in studyList)
{
t.SeriesList = await _repository.Where<DicomSeries>(s => s.StudyId == t.StudyId)
.WhereIf(isReading == 1, s => s.IsReading).OrderBy(s => s.SeriesNumber).
ThenBy(s => s.SeriesTime)
.ProjectTo<DicomSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
t.SeriesList.ForEach(series => series.InstanceList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k => k.Id).ToList());
//设置为阅片与否 不更改数据库检查 的instance数量 和 SeriesCount 所以这里要实时统计
t.SeriesCount = t.SeriesList.Count();
t.InstanceCount = t.SeriesList.SelectMany(t => t.InstanceList).Count();
}
return studyList;
//return ResponseOutput.Ok(studyList.Where(t => t.SeriesList.Count > 0).ToList());
}
}
}