From d9a85b6825f1c2bdb4e7f5927a67048d45ea43de Mon Sep 17 00:00:00 2001
From: hang <872297557@qq.com>
Date: Tue, 20 Aug 2024 17:58:24 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=B7=BB=E5=8A=A0pacs=20?=
=?UTF-8?q?=E5=BD=B1=E5=83=8F?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../IRaCIS.Core.Application.xml | 5 +-
.../Service/ImageAndDoc/StudyService.cs | 2 +
.../Service/Visit/DTO/PatientViewModel.cs | 13 +-
.../Service/Visit/DTO/VisitPointViewModel.cs | 12 +-
.../Service/Visit/PatientService.cs | 235 +++++++++++++++++-
5 files changed, 256 insertions(+), 11 deletions(-)
diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml
index 36374a2b0..4d68334dc 100644
--- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml
+++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml
@@ -15239,11 +15239,14 @@
-
+
提交 患者检查和访视的绑定
+
+
+
diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs
index cdd161e9b..7d7d8cbd1 100644
--- a/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs
+++ b/IRaCIS.Core.Application/Service/ImageAndDoc/StudyService.cs
@@ -206,6 +206,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);
@@ -280,6 +281,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;
diff --git a/IRaCIS.Core.Application/Service/Visit/DTO/PatientViewModel.cs b/IRaCIS.Core.Application/Service/Visit/DTO/PatientViewModel.cs
index 05d8d3fcc..2409b3028 100644
--- a/IRaCIS.Core.Application/Service/Visit/DTO/PatientViewModel.cs
+++ b/IRaCIS.Core.Application/Service/Visit/DTO/PatientViewModel.cs
@@ -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 SCPStudyIdList { get; set; }
}
+ public class SubmitVisitStudyBindingCommand: VerifyPacsImageCommand
+ {
+
+
+ public List ReUploadSCPStudyIdList { get; set; }
+ }
+
public class SubjectVisitSelectQuery
{
[NotDefault]
diff --git a/IRaCIS.Core.Application/Service/Visit/DTO/VisitPointViewModel.cs b/IRaCIS.Core.Application/Service/Visit/DTO/VisitPointViewModel.cs
index 92d44de4b..382023c91 100644
--- a/IRaCIS.Core.Application/Service/Visit/DTO/VisitPointViewModel.cs
+++ b/IRaCIS.Core.Application/Service/Visit/DTO/VisitPointViewModel.cs
@@ -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 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
{
diff --git a/IRaCIS.Core.Application/Service/Visit/PatientService.cs b/IRaCIS.Core.Application/Service/Visit/PatientService.cs
index 1d98ce922..2953f522f 100644
--- a/IRaCIS.Core.Application/Service/Visit/PatientService.cs
+++ b/IRaCIS.Core.Application/Service/Visit/PatientService.cs
@@ -54,10 +54,12 @@ namespace IRaCIS.Application.Services
private readonly IRepository _scpStudyRepository;
private readonly IRepository _subjectRepository;
private readonly IRepository _subjectVisitRepository;
+ private readonly IRepository _dictionaryRepository;
private readonly IDistributedLockProvider _distributedLockProvider;
- public PatientService(IRepository studyRepository, IRepository trialRepository, IRepository patientRepository, IRepository subjectRepository, IRepository subjectVisitRepository, IDistributedLockProvider distributedLockProvider)
+ public PatientService(IRepository studyRepository, IRepository dictionaryRepository, IRepository trialRepository, IRepository patientRepository, IRepository subjectRepository, IRepository subjectVisitRepository, IDistributedLockProvider distributedLockProvider)
{
+ _dictionaryRepository = dictionaryRepository;
_scpStudyRepository = studyRepository;
_trialRepository = trialRepository;
_patientRepository = patientRepository;
@@ -75,7 +77,7 @@ namespace IRaCIS.Application.Services
[HttpPost]
public async Task>> GetSCPImageUploadList(SCPImageUploadQuery inQuery)
{
- var query = _repository.Where(t=>t.TrialId==inQuery.TrialId)
+ var query = _repository.Where(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> VerifyPacsImage(VerifyPacsImageCommand inCommand)
+ {
+ var trialId = inCommand.TrialId;
+
+ var subjectId = inCommand.SubjectId;
+
+ var isVerifyVisitImageDate = await _repository.Where(t => t.Id == inCommand.TrialId).Select(t => t.IsVerifyVisitImageDate).FirstNotNullAsync();
+
+ var result = new List();
+
+ var visitList = _repository.Where(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(t => t.TrialId == trialId && t.Id == waitUploadItem.Id).ProjectTo(_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;
+
+
+ }
+
+
+
///
/// 提交 患者检查和访视的绑定
///
///
+ ///
+ ///
+ ///
///
[HttpPost]
[UnitOfWork]
[TypeFilter(typeof(TrialResourceFilter), Arguments = new object[] { "AfterStopCannNotOpt" })]
- public async Task SubmitVisitStudyBinding(SubmitVisitStudyBindingCommand inCommand)
+ public async Task SubmitVisitStudyBinding(SubmitVisitStudyBindingCommand inCommand,
+ [FromServices]IRepository _dicomstudyRepository,
+ [FromServices] IRepository _dicomSeriesRepository,
+ [FromServices] IRepository _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(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(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(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(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(t => t.Id == scpStudy.PatientId, u => new SCPPatient() { SubjectId = subjectId });
+ await _repository.BatchUpdateAsync(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