305 lines
13 KiB
C#
305 lines
13 KiB
C#
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());
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
}
|
||
}
|