修改添加pacs 影像

IRC_NewDev
hang 2024-08-20 17:58:24 +08:00
parent 1937804e47
commit aa9df5838c
5 changed files with 256 additions and 11 deletions

View File

@ -15192,11 +15192,14 @@
<param name="inQuery"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Application.Services.PatientService.SubmitVisitStudyBinding(IRaCIS.Application.Contracts.SubmitVisitStudyBindingCommand)">
<member name="M:IRaCIS.Application.Services.PatientService.SubmitVisitStudyBinding(IRaCIS.Application.Contracts.SubmitVisitStudyBindingCommand,IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomStudy},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomSeries},IRaCIS.Core.Infra.EFCore.IRepository{IRaCIS.Core.Domain.Models.DicomInstance})">
<summary>
提交 患者检查和访视的绑定
</summary>
<param name="inCommand"></param>
<param name="_dicomstudyRepository"></param>
<param name="_dicomSeriesRepository"></param>
<param name="_dicomInstanceRepository"></param>
<returns></returns>
</member>
<member name="M:IRaCIS.Application.Services.SubjectService.AddOrUpdateSubject(IRaCIS.Application.Contracts.SubjectCommand)">

View File

@ -205,6 +205,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
study.TrialId = incommand.TrialId;
study.SubjectId = incommand.SubjectId;
study.SubjectVisitId = incommand.SubjectVisitId;
study.IsFromPACS = false;
//如果因为意外情况,连续点击两次,导致第一次插入了,第二次进来也会插入,在此判断一下
var findStudy = await _dicomstudyRepository.FirstOrDefaultAsync(t => t.Id == study.Id);
@ -279,6 +280,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc
studyMonitor.StudyCode = study.StudyCode;
//特殊处理逻辑
study.IsFromPACS = false;
study.Modalities = string.Join("、", incommand.Study.SeriesList.Select(t => t.Modality).Union(study.Modalities.Split("、", StringSplitOptions.RemoveEmptyEntries)).Distinct());
SpecialArchiveStudyDeal(study);
modalitys = study.Modalities;

View File

@ -256,9 +256,9 @@ namespace IRaCIS.Application.Contracts
public string? TrialSiteCode { get; set; }
public string? TrialSiteName { get; set; }
public string? TrialSiteName { get; set; }
public string? TrialSiteAliasName { get; set; }
public string? TrialSiteAliasName { get; set; }
}
@ -382,7 +382,7 @@ namespace IRaCIS.Application.Contracts
}
public class SubmitVisitStudyBindingCommand
public class VerifyPacsImageCommand
{
[NotDefault]
public Guid TrialId { get; set; }
@ -396,6 +396,13 @@ namespace IRaCIS.Application.Contracts
public List<Guid> SCPStudyIdList { get; set; }
}
public class SubmitVisitStudyBindingCommand: VerifyPacsImageCommand
{
public List<Guid> ReUploadSCPStudyIdList { get; set; }
}
public class SubjectVisitSelectQuery
{
[NotDefault]

View File

@ -264,7 +264,7 @@ namespace IRaCIS.Core.Application.Contracts
public bool IsCriticalSequence { get; set; } = false;
public int SeriesCount =>SeriesList.Count;
public int SeriesCount => SeriesList.Count;
public int InstanceCount { get; set; }
public bool IsDicom { get; set; } = true;
@ -369,6 +369,16 @@ namespace IRaCIS.Core.Application.Contracts
public List<string> SOPInstanceUIDList { get; set; }
}
public class VerifySCPStudyUploadResult
{
public Guid SCPStudyId { get; set; }
public string ErrorMesseage { get; set; } = String.Empty;
public bool AllowUpload { get; set; } = false;
public bool AllowReUpload { get; set; } = false;
}
public class VerifyStudyUploadResult
{

View File

@ -54,10 +54,12 @@ namespace IRaCIS.Application.Services
private readonly IRepository<SCPStudy> _scpStudyRepository;
private readonly IRepository<Subject> _subjectRepository;
private readonly IRepository<SubjectVisit> _subjectVisitRepository;
private readonly IRepository<Dictionary> _dictionaryRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
public PatientService(IRepository<SCPStudy> studyRepository, IRepository<Trial> trialRepository, IRepository<SCPPatient> patientRepository, IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository, IDistributedLockProvider distributedLockProvider)
public PatientService(IRepository<SCPStudy> studyRepository, IRepository<Dictionary> dictionaryRepository, IRepository<Trial> trialRepository, IRepository<SCPPatient> patientRepository, IRepository<Subject> subjectRepository, IRepository<SubjectVisit> subjectVisitRepository, IDistributedLockProvider distributedLockProvider)
{
_dictionaryRepository = dictionaryRepository;
_scpStudyRepository = studyRepository;
_trialRepository = trialRepository;
_patientRepository = patientRepository;
@ -75,7 +77,7 @@ namespace IRaCIS.Application.Services
[HttpPost]
public async Task<IResponseOutput<PageOutput<SCPImageUploadView>>> GetSCPImageUploadList(SCPImageUploadQuery inQuery)
{
var query = _repository.Where<SCPImageUpload>(t=>t.TrialId==inQuery.TrialId)
var query = _repository.Where<SCPImageUpload>(t => t.TrialId == inQuery.TrialId)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CalledAE), t => t.CalledAE.Contains(inQuery.CalledAE))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAEIP), t => t.CallingAEIP.Contains(inQuery.CallingAEIP))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAE), t => t.CallingAE.Contains(inQuery.CallingAE))
@ -283,23 +285,120 @@ namespace IRaCIS.Application.Services
public async Task<List<VerifySCPStudyUploadResult>> VerifyPacsImage(VerifyPacsImageCommand inCommand)
{
var trialId = inCommand.TrialId;
var subjectId = inCommand.SubjectId;
var isVerifyVisitImageDate = await _repository.Where<Trial>(t => t.Id == inCommand.TrialId).Select(t => t.IsVerifyVisitImageDate).FirstNotNullAsync();
var result = new List<VerifySCPStudyUploadResult>();
var visitList = _repository.Where<SubjectVisit>(t => t.SubjectId == inCommand.SubjectId).Select(t => new { t.VisitNum, t.EarliestScanDate, t.LatestScanDate, t.Id }).ToList();
var currentVisitNum = visitList.First(t => t.Id == inCommand.SubjectVisitId).VisitNum;
var scpStudyList = _scpStudyRepository.Where(t => inCommand.SCPStudyIdList.Contains(t.Id)).Select(t => new { StudyDate = t.StudyTime, t.Id }).ToList();
foreach (var waitUploadItem in scpStudyList)
{
if (isVerifyVisitImageDate)
{
//小于当前访视 最近的最晚拍片
var before = visitList.Where(u => u.VisitNum < currentVisitNum).Max(k => k.LatestScanDate);
if (before != null && waitUploadItem.StudyDate != null && before > waitUploadItem.StudyDate)
{
// $"当前访视检查时间{waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")}不能早于前序访视检查时间{before?.ToString("yyyy-MM-dd")},请核对检查数据是否有误",
result.Add(new VerifySCPStudyUploadResult() { ErrorMesseage = _localizer["Study_VisitBeforePrevError", waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")!, before?.ToString("yyyy-MM-dd")!] });
}
//大于当前访视 最近的最早拍片日期
var after = visitList.Where(u => u.VisitNum > currentVisitNum).Min(k => k.EarliestScanDate);
if (after != null && waitUploadItem.StudyDate != null && after < waitUploadItem.StudyDate)
{
// $"当前访视检查时间{waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")}不能晚于该访视之后的检查时间{after?.ToString("yyyy-MM-dd")},请核对检查数据是否有误"
result.Add(new VerifySCPStudyUploadResult() { ErrorMesseage = _localizer["Study_VisitAfterSubseqError", waitUploadItem.StudyDate?.ToString("yyyy-MM-dd")!, after?.ToString("yyyy-MM-dd")!]});
}
}
var verifyStudyInfo = _repository.Where<DicomStudy>(t => t.TrialId == trialId && t.Id == waitUploadItem.Id).ProjectTo<VerifyStudyDto>(_mapper.ConfigurationProvider).FirstOrDefault();
var currentStudyResult = new VerifyStudyUploadResult();
//数据库不存在该检查 允许上传
if (verifyStudyInfo == null)
{
currentStudyResult.AllowUpload = true;
}
//数据库该项目有该检查 看是否支持重传
else
{
//是同一个受试者 支持重传
if (verifyStudyInfo.SubjectId == subjectId && verifyStudyInfo.SubjectVisitId == inCommand.SubjectVisitId)
{
currentStudyResult.AllowReUpload = true;
}
//不是同一个受试者
else
{
//有默认值,其实不用写,这里为了好理解
currentStudyResult.AllowUpload = false;
currentStudyResult.AllowReUpload = false;
//$"此处不可以上传。当前影像检查已经上传给受试者{verifyStudyInfo.SubjectCode}的{verifyStudyInfo.VisitName}"
currentStudyResult.ErrorMesseage = _localizer["Study_ImgAlreadyUploaded", verifyStudyInfo.SubjectCode, verifyStudyInfo.VisitName];
}
}
}
return result;
}
/// <summary>
/// 提交 患者检查和访视的绑定
/// </summary>
/// <param name="inCommand"></param>
/// <param name="_dicomstudyRepository"></param>
/// <param name="_dicomSeriesRepository"></param>
/// <param name="_dicomInstanceRepository"></param>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
public async Task<IResponseOutput> SubmitVisitStudyBinding(SubmitVisitStudyBindingCommand inCommand)
public async Task<IResponseOutput> SubmitVisitStudyBinding(SubmitVisitStudyBindingCommand inCommand,
[FromServices]IRepository<DicomStudy> _dicomstudyRepository,
[FromServices] IRepository<DicomSeries> _dicomSeriesRepository,
[FromServices] IRepository<DicomInstance> _dicomInstanceRepository)
{
//这里要做校验 + 同时验证本地系统里面的影像是否存在pacs推过来的
var copyCommand = inCommand.Clone();
copyCommand.SCPStudyIdList = inCommand.SCPStudyIdList.Union(inCommand.ReUploadSCPStudyIdList).ToList();
var verifyResult = await VerifyPacsImage(copyCommand);
var allowUploadList = verifyResult.Where(u => u.AllowUpload == true).Select(t => t.SCPStudyId).ToList();
var allowReUploadList = verifyResult.Where(u => u.AllowReUpload == true).Select(t => t.SCPStudyId).ToList();
if (inCommand.SCPStudyIdList.All(t => allowUploadList.Contains(t)) && inCommand.ReUploadSCPStudyIdList.All(t => allowReUploadList.Contains(t)))
{
throw new BusinessValidationFailedException("对接提示: 前端提交的检查有不能上传的,请刷新页面调用验证接口重试!");
}
var subjectId = inCommand.SubjectId;
var subjectVisitId = inCommand.SubjectVisitId;
var trialId = inCommand.TrialId;
var @lock = _distributedLockProvider.CreateLock($"StudyCode");
using (await @lock.AcquireAsync())
@ -308,6 +407,7 @@ namespace IRaCIS.Application.Services
int currentNextCodeInt = dbStudyCodeIntMax + 1;
//新增的,上传的
foreach (var scpStudyId in inCommand.SCPStudyIdList)
{
@ -315,7 +415,6 @@ namespace IRaCIS.Application.Services
if (find != null)
{
var newStuty = _mapper.Map<DicomStudy>(find.SCPStudy);
await _repository.AddAsync(newStuty);
@ -362,6 +461,93 @@ namespace IRaCIS.Application.Services
}
foreach (var scpStudyId in inCommand.ReUploadSCPStudyIdList)
{
var study = await _dicomstudyRepository.FirstOrDefaultAsync(t => t.Id == scpStudyId);
var instanceIdList = _dicomInstanceRepository.Where(t => t.Id == scpStudyId).Select(t => t.Id).ToList();
var scpStudy = _scpStudyRepository.Where(t => t.Id == scpStudyId).Include(t=>t.SeriesList).ThenInclude(t=>t.SCPInstanceList).FirstOrDefault();
//以最后一次为准
study.IsFromPACS = true;
//特殊处理逻辑
study.Modalities = string.Join("、", scpStudy.SeriesList.Select(t => t.Modality).Union(study.Modalities.Split("、", StringSplitOptions.RemoveEmptyEntries)).Distinct());
SpecialArchiveStudyDeal(study);
// 少了整个序列
//某个序列下少了instance
foreach (var seriesItem in scpStudy.SeriesList)
{
var seriesId = IdentifierHelper.CreateGuid(seriesItem.StudyInstanceUid, seriesItem.SeriesInstanceUid, trialId.ToString());
DicomSeries dicomSeries = await _dicomSeriesRepository.FirstOrDefaultAsync(t => t.Id == seriesId);
//判断重复
if (dicomSeries == null)
{
var series = _mapper.Map<DicomSeries>(seriesItem);
series.SeqId = Guid.Empty;
series.TrialId = trialId;
series.SubjectId = subjectId;
series.SubjectVisitId = subjectVisitId;
dicomSeries = await _dicomSeriesRepository.AddAsync(series);
foreach (var instanceItem in seriesItem.SCPInstanceList)
{
var instance = _mapper.Map<DicomInstance>(instanceItem);
instance.SeqId = Guid.Empty;
instance.TrialId = trialId;
instance.SubjectId = subjectId;
instance.SubjectVisitId = subjectVisitId;
await _dicomInstanceRepository.AddAsync(instance);
}
//新的序列 那么 检查的序列数量+1
study.SeriesCount += 1;
study.InstanceCount += seriesItem.SCPInstanceList.Count;
}
else
{
//该序列掉了instance
dicomSeries.InstanceCount += seriesItem.SCPInstanceList.Count;
var newInstanceList = seriesItem.SCPInstanceList.Where(t => !instanceIdList.Contains(t.Id));
foreach (var instanceItem in newInstanceList)
{
var instance = _mapper.Map<DicomInstance>(instanceItem);
instance.SeqId = Guid.Empty;
instance.TrialId = trialId;
instance.SubjectId = subjectId;
instance.SubjectVisitId = subjectVisitId;
await _dicomInstanceRepository.AddAsync(instance);
}
study.InstanceCount += newInstanceList.Count();
}
}
await _repository.SaveChangesAsync();
await _repository.BatchUpdateAsync<SCPPatient>(t => t.Id == scpStudy.PatientId, u => new SCPPatient() { SubjectId = subjectId });
await _repository.BatchUpdateAsync<SCPStudy>(t => t.Id == scpStudyId, u => new SCPStudy() { SubjectVisitId = subjectVisitId });
}
}
@ -373,6 +559,43 @@ namespace IRaCIS.Application.Services
return ResponseOutput.Ok();
}
private void SpecialArchiveStudyDeal(DicomStudy study)
{
#region 特殊逻辑
if (study.PatientBirthDate.Length == 8)
{
study.PatientBirthDate = $"{study.PatientBirthDate[0]}{study.PatientBirthDate[1]}{study.PatientBirthDate[2]}{study.PatientBirthDate[3]}-{study.PatientBirthDate[4]}{study.PatientBirthDate[5]}-{study.PatientBirthDate[6]}{study.PatientBirthDate[7]}";
}
var dicModalityList = _dictionaryRepository.Where(t => t.Code == "Modality").SelectMany(t => t.ChildList.Select(c => c.Value)).ToList();
var modality = study.Modalities;
var modalityForEdit = dicModalityList.Contains(modality) ? modality : String.Empty;
if (modality == "MR")
{
modalityForEdit = "MRI";
}
if (modality == "PT")
{
modalityForEdit = "PET";
}
if (modality == "PT、CT")
{
modalityForEdit = "PET-CT";
}
study.ModalityForEdit = modalityForEdit;
#endregion
}
#endregion