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

3408 lines
163 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.Application.Interfaces;
using IRaCIS.Application.Contracts;
using IRaCIS.Core.Application.Filter;
using IRaCIS.Core.Domain.Share;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using IRaCIS.Core.Application.Auth;
using MassTransit;
using Panda.DynamicWebApi.Attributes;
using DocumentFormat.OpenXml.Spreadsheet;
using AutoMapper.EntityFrameworkCore;
using IRaCIS.Core.Domain.Models;
using IRaCIS.Core.Application.Service.Reading.Dto;
using Microsoft.Extensions.Options;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SharpCompress.Common;
using System.Reactive.Subjects;
using Subject = IRaCIS.Core.Domain.Models.Subject;
using IRaCIS.Core.Application.ViewModel;
using Medallion.Threading;
using IRaCIS.Core.Infrastructure;
using IRaCIS.Core.Application.Contracts;
using MailKit.Search;
using DocumentFormat.OpenXml.Office2010.Excel;
using IRaCIS.Core.Application.Contracts.Dicom.DTO;
using IRaCIS.Core.Application.Helper;
using NPOI.SS.Formula.Functions;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Text;
using DocumentFormat.OpenXml.EMMA;
using Azure;
using System.IO.Compression;
using static IRaCIS.Core.Domain.Share.StaticData;
using FellowOakDicom;
using DocumentFormat.OpenXml.Office2010.Drawing;
using IDistributedLockProvider = Medallion.Threading.IDistributedLockProvider;
using DocumentFormat.OpenXml.InkML;
using Microsoft.AspNetCore.Hosting;
using IRaCIS.Core.Infrastructure.Encryption;
using FellowOakDicom.Network.Client;
using FellowOakDicom.Network;
using Microsoft.Extensions.Logging;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using static Microsoft.EntityFrameworkCore.DbLoggerCategory;
using DocumentFormat.OpenXml.Vml.Office;
using IRaCIS.Core.Infra.EFCore.Migrations;
using System.Dynamic;
using System.Threading.Channels;
using NPOI.HSSF.Record.Chart;
namespace IRaCIS.Application.Services
{
[ApiExplorerSettings(GroupName = "Trial")]
public class PatientService(IRepository<SCPStudySubjectVisit> _studySubjectVisitRepository,
IRepository<SubjectPatient> _subjectPatientRepository,
IRepository<Trial> _trialRepository,
IRepository<SCPPatient> _patientRepository,
IRepository<SCPStudy> _studyRepository,
IRepository<Subject> _subjectRepository,
IRepository<SubjectVisit> _subjectVisitRepository,
IRepository<SubejctVisitDownload> _subejctVisitDownloadRepository,
IRepository<SCPImageUpload> _SCPImageUploadRepository,
IRepository<User> _userRepository,
IRepository<HIRHospital> _hIRHospitalRepository,
ILogger<PatientService> _logger,
IDistributedLockProvider _distributedLockProvider, IMapper _mapper, IUserInfo _userInfo, IWebHostEnvironment _hostEnvironment, IStringLocalizer _localizer, IFusionCache _fusionCache
) : BaseService
{
#region 医院信息管理
/// <summary>
/// 获取医院的配置信息
/// </summary>
/// <returns></returns>
[AllowAnonymous]
public async Task<HIRHospitalView> GetHospitalInfo()
{
var query = _hIRHospitalRepository.Where(t => t.IsDefault == true).ProjectTo<HIRHospitalView>(_mapper.ConfigurationProvider);
return await query.FirstNotNullAsync();
}
[AllowAnonymous]
[HttpPut]
public async Task<IResponseOutput> UpdateDefaultHospital(Guid hirHospitalId)
{
await _hIRHospitalRepository.BatchUpdateNoTrackingAsync(t => t.Id != hirHospitalId, u => new HIRHospital() { IsDefault = false });
await _hIRHospitalRepository.BatchUpdateNoTrackingAsync(t => t.Id == hirHospitalId, u => new HIRHospital() { IsDefault = true });
return ResponseOutput.Ok();
}
[AllowAnonymous]
[HttpPost]
public async Task<PageOutput<HIRHospitalView>> GetHIRHospitalList(HIRHospitalQuery inQuery)
{
var hIRHospitalQueryable = _hIRHospitalRepository
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.HospitalName), t => t.HospitalName.Contains(inQuery.HospitalName) || t.HospitalAliasName.Contains(inQuery.HospitalName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Country), t => t.Country.Contains(inQuery.Country))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.City), t => t.City.Contains(inQuery.Country))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Phone), t => t.Phone.Contains(inQuery.Phone))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Province), t => t.Province.Contains(inQuery.Province))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Address), t => t.Address.Contains(inQuery.Address))
.ProjectTo<HIRHospitalView>(_mapper.ConfigurationProvider);
var list = await hIRHospitalQueryable.ToPagedListAsync(inQuery);
return list;
}
public async Task<IResponseOutput> AddOrUpdateHIRHospital(HIRHospitalAddOrEdit addOrEditHIRHospital)
{
var exp = new EntityVerifyExp<HIRHospital>()
{
VerifyExp = h => h.IsDefault.Equals(addOrEditHIRHospital.IsDefault),
//"默认医院只允许一个"
VerifyMsg = _localizer["Patient_OnlyOneDefaultHospital"]
};
var exp2 = new EntityVerifyExp<HIRHospital>()
{
VerifyExp = h => h.HospitalCode.Equals(addOrEditHIRHospital.HospitalCode) ||
h.HospitalName.Equals(addOrEditHIRHospital.HospitalName) ||
h.HospitalAliasName.Equals(addOrEditHIRHospital.HospitalAliasName),
//医院编码、名称不能重复
VerifyMsg = _localizer["Patient_RepeatHospitalCodeOrName"]
};
var entity = await _hIRHospitalRepository.InsertOrUpdateAsync(addOrEditHIRHospital, true, exp, exp2);
return ResponseOutput.Ok(entity.Id.ToString());
}
[HttpDelete("{hIRHospitalId:guid}")]
public async Task<IResponseOutput> DeleteHIRHospital(Guid hIRHospitalId)
{
var success = await _hIRHospitalRepository.DeleteFromQueryAsync(t => t.Id == hIRHospitalId, true);
return ResponseOutput.Ok();
}
#endregion
#region 项目管理
/// <summary>
/// 获取系统已确认的标准
/// </summary>
/// <param name="_readingQuestionCriterionSystemRepository"></param>
/// <returns></returns>
public async Task<IResponseOutput> GetSystemConfirmedCreiterionList([FromServices] IRepository<ReadingQuestionCriterionSystem> _readingQuestionCriterionSystemRepository)
{
var list = await _readingQuestionCriterionSystemRepository.Where(x => x.IsEnable && x.IsCompleteConfig).OrderBy(t => t.ShowOrder).Select(t => new { t.CriterionType, t.CriterionName, t.Id, t.Description }).ToListAsync();
return ResponseOutput.Ok(list);
}
/// <summary>
/// 获取项目列表 PM CRC 共用)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<NewTrialView>>> GetTrialList(NewTrialQuery inQuery)
{
var trialQuery = _trialRepository
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.ResearchProgramNo), t => t.ResearchProgramNo.Contains(inQuery.ResearchProgramNo))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.ExperimentName), t => t.ExperimentName.Contains(inQuery.ExperimentName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SponsorName), t => t.Sponsor.Contains(inQuery.SponsorName))
.WhereIf(inQuery.TrialType != null, t => t.TrialType == inQuery.TrialType)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.TrialCode), t => t.TrialCode.Contains(inQuery.TrialCode))
.WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.Admin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.OA
, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id && t.IsDeleted == false) && t.IsDeleted == false)
.ProjectTo<NewTrialView>(_mapper.ConfigurationProvider);
var pageList = await trialQuery.ToPagedListAsync(inQuery, nameof(NewTrialQuery.ResearchProgramNo));
return ResponseOutput.Ok(pageList);
}
[HttpGet("{trialId:guid}")]
public async Task<IResponseOutput> GetTrialInfo(Guid trialId, [FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig)
{
var trial = (await _trialRepository.Where(o => o.Id == trialId).IgnoreQueryFilters().ProjectTo<TrialInfoDTO>(_mapper.ConfigurationProvider, new { isEn_Us = _userInfo.IsEn_Us }).FirstOrDefaultAsync()).IfNullThrowException();
if (!string.IsNullOrEmpty(trial.AuthorizationEncrypt))
{
try
{
//解析加密信息
var decodedText = AesEncryption.Decrypt(trial.AuthorizationEncrypt, _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
return ResponseOutput.Ok(trial, authInfo);
}
catch (Exception)
{
return ResponseOutput.Ok(trial, msg: "项目未授权,请确认。", code: ApiResponseCodeEnum.NeedTips);
}
}
return ResponseOutput.Ok(trial);
}
/// <summary>
/// 添加更新项目
/// </summary>
/// <param name="inCommand"></param>
/// <param name="_systemEmailSendConfig"></param>
/// <param name="_provider"></param>
/// <returns></returns>
/// <exception cref="BusinessValidationFailedException"></exception>
[HttpPost]
[UnitOfWork]
public async Task<IResponseOutput> AddOrUpdateTrial(AddOrUpdateTrialCommand inCommand,
[FromServices] IOptionsMonitor<SystemEmailSendConfig> _systemEmailSendConfig,
[FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig,
[FromServices] IOptionsMonitor<SystemHospitalOption> _systemHospitalOption,
[FromServices] IRepository<TrialDictionary> _trialDictionaryRepository,
[FromServices] IRepository<TrialUser> _trialUserRepository,
[FromServices] IFusionCache _provider)
{
var code = _systemHospitalOption.CurrentValue.HospitalCode;
//if (await _trialRepository.CountAsync(u => u.TrialStatusStr == StaticData.TrialState.TrialOngoing) > _systemHospitalOption.CurrentValue.TrialKeepCount)
//{
// throw new BusinessValidationFailedException($"已超过当前系统配置的未启动项目数量的限制,您的操作被限制,请获取授权再进行操作!");
//}
inCommand.ResearchProgramNo = inCommand.ResearchProgramNo.Trim();
if (inCommand.Id == Guid.Empty || inCommand.Id == null)
{
if (await _trialRepository.AnyAsync(u => u.TrialCode == inCommand.TrialCode))
{
//---已经存在相同的项目编号。
throw new BusinessValidationFailedException(_localizer["Trial_DuplicateProjectNumber"]);
}
foreach (var criterionType in inCommand.CriterionTypeList)
{
if (await _trialRepository.AnyAsync(u => u.ResearchProgramNo == inCommand.ResearchProgramNo && u.CriterionTypes.Contains($"|{(int)criterionType}|")))
{
throw new BusinessValidationFailedException($"已存在研究方案号为{inCommand.ResearchProgramNo},该标准的项目");
}
}
var dbMaxCode = await _trialRepository.Where(t => t.CreateTime.Year == DateTime.Now.Year && t.TrialType == inCommand.TrialType).Select(t => t.Code).DefaultIfEmpty().MaxAsync();
var currentYearMaxCodeNext = dbMaxCode + 1;
var trial = _mapper.Map<Trial>(inCommand);
//trial.Id = NewId.NextGuid();
var yearStr = DateTime.Now.Year.ToString();
trial.Code = currentYearMaxCodeNext;
trial.TrialCode = (trial.TrialType == TrialType.ScientificResearch ? $"Z{code}RT" : $"Z{code}CT") + yearStr.Substring(yearStr.Length - 2) + currentYearMaxCodeNext.ToString("D3");
trial.CriterionTypes = $"|{string.Join('|', inCommand.CriterionTypeList.Select(x => ((int)x).ToString()).ToList())}|";
//多选信息
inCommand.ModalityIds.ForEach(modalityId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = modalityId, KeyName = StaticData.Modality, TrialId = trial.Id }));
//添加项目后 项目状态变更为申请下载简历
trial.TrialEnrollStatus = (int)TrialEnrollStatus.ChooseDoctor;
trial = await _trialRepository.AddAsync(trial);
//如果是PM 则需要将该人员添加到 运维人员表
//添加运维人员PM
await _trialUserRepository.AddAsync(new TrialUser() { TrialId = trial.Id, UserId = _userInfo.Id, JoinTime = DateTime.Now });
//默认采用系统邮件
trial.EmailAuthorizationCode = _systemEmailSendConfig.CurrentValue.AuthorizationCode;
trial.EmailFromEmail = _systemEmailSendConfig.CurrentValue.FromEmail;
trial.EmailFromName = _systemEmailSendConfig.CurrentValue.FromName;
trial.EmailSMTPServerAddress = _systemEmailSendConfig.CurrentValue.Host;
trial.EmailSMTPServerPort = _systemEmailSendConfig.CurrentValue.Port;
trial.IsConfigureEmail = true;
trial.CreateTime = DateTime.Now;
var success = await _trialRepository.SaveChangesAsync();
var caheInfo = new TrialCacheInfo() { TrialId = trial.Id, TrialStatusStr = trial.TrialStatusStr, CriterionTypes = trial.CriterionTypes, AuthorizationEncrypt = trial.AuthorizationEncrypt, AuthorizationDate = trial.AuthorizationDate, CreateUserId = trial.CreateUserId, TrialCode = trial.TrialCode };
await _provider.SetAsync(trial.Id.ToString(), caheInfo, TimeSpan.FromDays(7));
return ResponseOutput.Ok(trial);
}
else
{
var updateModel = inCommand;
foreach (var criterionType in inCommand.CriterionTypeList)
{
if (await _trialRepository.AnyAsync(u => u.ResearchProgramNo == inCommand.ResearchProgramNo && u.CriterionTypes.Contains($"|{(int)criterionType}|") && u.Id != updateModel.Id))
{
throw new BusinessValidationFailedException($"已存在研究方案号为{inCommand.ResearchProgramNo},该标准的项目");
}
}
if (!await _trialRepository.AnyAsync(u => u.Id == inCommand.Id && (u.TrialStatusStr == StaticData.TrialState.TrialInitializing || u.TrialStatusStr == StaticData.TrialState.TrialOngoing)))
{
//---项目状态只有处于:初始化或者进行中时,才允许操作。
throw new BusinessValidationFailedException(_localizer["Trial_InvalidProjectStatus"]);
}
// 判断项目Id 是否已经存在
if (await _trialRepository.AnyAsync(u => u.TrialCode == updateModel.TrialCode && u.Id != updateModel.Id))
{
//---已经存在相同的项目编号。
throw new BusinessValidationFailedException(_localizer["Trial_DuplicateProjectNumber"]);
}
var trial = await _trialRepository.FirstOrDefaultAsync(t => t.Id == updateModel.Id);
//删除中间表 Title对应的记录
await _trialDictionaryRepository.BatchDeleteNoTrackingAsync(t => t.TrialId == updateModel.Id);
//重新插入新的 Title记录
updateModel.ModalityIds.ForEach(modalityId => trial.TrialDicList.Add(new TrialDictionary() { DictionaryId = modalityId, KeyName = StaticData.Modality, TrialId = trial.Id }));
_mapper.Map(updateModel, trial);
trial.CriterionTypes = $"|{string.Join('|', inCommand.CriterionTypeList.Select(x => ((int)x).ToString()).ToList())}|";
var caheInfo = new TrialCacheInfo() { TrialId = trial.Id, TrialStatusStr = trial.TrialStatusStr, CriterionTypes = trial.CriterionTypes, AuthorizationEncrypt = trial.AuthorizationEncrypt, AuthorizationDate = trial.AuthorizationDate, CreateUserId = trial.CreateUserId, TrialCode = trial.TrialCode };
await _provider.SetAsync(trial.Id.ToString(), caheInfo, TimeSpan.FromDays(7));
var success = await _trialRepository.SaveChangesAsync();
return ResponseOutput.Ok(trial);
}
}
#endregion
#region 授权和激活
public async Task<IResponseOutput<TrialAuthorizationInfo>> GetTrialAuthorizationInfo(Guid trialId, [FromServices] IOptionsMonitor<SystemHospitalOption> _hospitalOption)
{
var trialInfo = _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).FirstOrDefault();
var authInfo = new TrialAuthorizationInfo()
{
TrialId = trialInfo.Id,
TrialCode = trialInfo.TrialCode,
CreateUserId = trialInfo.CreateUserId,
PurchaseDuration = 1,
CriterionTypeList = trialInfo.CriterionTypeList,
//CriterionTypes = trialInfo.CriterionTypes,
HospitalName = _hospitalOption.CurrentValue.HospitalName,
HospitalCode = _hospitalOption.CurrentValue.HospitalCode,
};
return ResponseOutput.Ok(authInfo);
}
/// <summary>
/// 获取项目授权码
/// </summary>
/// <param name="authInfo"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> GetTrialAuthorizationCode(TrialAuthorizationInfo authInfo, [FromServices] IOptionsMonitor<SystemHospitalOption> _hospitalOption)
{
// 将明文信息转换成 Base64 编码
string base64EncodedText = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(authInfo)));
return ResponseOutput.Ok(base64EncodedText);
}
/// <summary>
/// 获取授权码明文信息
/// </summary>
/// <param name="authorizationCode"></param>
/// <param name="_hospitalOption"></param>
/// <returns></returns>
[AllowAnonymous]
public async Task<IResponseOutput> GetAuthorizationCodeInfo(string authorizationCode, [FromServices] IOptionsMonitor<SystemHospitalOption> _hospitalOption)
{
// 解密 Base64 编码后的数据
byte[] base64DecodedBytes = Convert.FromBase64String(authorizationCode);
string decodedText = System.Text.Encoding.UTF8.GetString(base64DecodedBytes);
var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
if (authInfo == null)
{
return ResponseOutput.NotOk("不能解析该项目授权码");
}
return ResponseOutput.Ok(authInfo);
}
/// <summary>
/// 获取项目激活码
/// </summary>
/// <param name="authorizationInfo"></param>
/// <param name="_basicSystemConfigConfig"></param>
/// <returns></returns>
[AllowAnonymous]
[HttpPost]
public async Task<IResponseOutput> GetTrialActivationCode(TrialAuthorizationInfo authorizationInfo, [FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig)
{
authorizationInfo.ActiveDeadLineDate = DateTime.Now.Date.AddDays(8).AddSeconds(-1);
var info = AesEncryption.Encrypt($"{JsonConvert.SerializeObject(authorizationInfo)}", _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
return ResponseOutput.Ok(info);
}
/// <summary>
/// 激活码获取明文信息
/// </summary>
/// <param name="activationCode"></param>
/// <param name="_hospitalOption"></param>
/// <param name="_basicSystemConfigConfig"></param>
/// <returns></returns>
public async Task<IResponseOutput> GetActivationCodeInfo(string activationCode,
[FromServices] IOptionsMonitor<SystemHospitalOption> _hospitalOption,
[FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig)
{
var decodedText = string.Empty;
try
{
decodedText = AesEncryption.Decrypt(activationCode, _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
}
catch (Exception)
{
return ResponseOutput.NotOk("激活码有误,请核对,无法激活");
}
var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
if (authInfo != null)
{
return ResponseOutput.Ok(authInfo);
}
else
{
return ResponseOutput.NotOk("激活码信息有误!");
}
}
/// <summary>
/// 设置项目授权信息
/// </summary>
/// <param name="trialId"></param>
/// <param name="activationCode"></param>
/// <returns></returns>
[HttpPut]
public async Task<IResponseOutput> ActivateTrial(Guid trialId, string activationCode,
[FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig,
[FromServices] IFusionCache _provider,
[FromServices] IOptionsMonitor<SystemHospitalOption> _hospitalOption)
{
var hospitalCode = _hospitalOption.CurrentValue.HospitalCode;
var trialInfo = _trialRepository.Where(t => t.Id == trialId, ignoreQueryFilters: true).FirstOrDefault();
var decodedText = string.Empty;
try
{
decodedText = AesEncryption.Decrypt(activationCode, _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
}
catch (Exception)
{
return ResponseOutput.NotOk("激活码有误,请核对,无法激活");
}
var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
if (authInfo != null)
{
if (authInfo.TrialCode != trialInfo.TrialCode || authInfo.CreateUserId != trialInfo.CreateUserId || authInfo.HospitalCode != hospitalCode ||
authInfo.TrialId != trialInfo.Id || trialInfo.CriterionTypeList.Except(authInfo.CriterionTypeList).Count() != 0)
{
return ResponseOutput.NotOk("该授权码与该项目不匹配");
}
if (DateTime.Now > authInfo.ActiveDeadLineDate)
{
return ResponseOutput.NotOk($"当前时间{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}超过激活时间{authInfo.ActiveDeadLineDate.Value.ToString("yyyy-MM-dd HH:mm:ss")},请联系授权方重新获取激活码");
}
//截止日期
var deadLineDate = DateTime.Now.Date.AddMonths(authInfo.PurchaseDuration).AddDays(1).AddSeconds(-1);
authInfo.AuthorizationDeadLineDate = deadLineDate;
authInfo.ActiveTime = DateTime.Now;
var newActivationCode = AesEncryption.Encrypt($"{JsonConvert.SerializeObject(authInfo)}", _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
await _trialRepository.BatchUpdateNoTrackingAsync(t => t.Id == trialId, u => new Trial() { AuthorizationEncrypt = newActivationCode, AuthorizationDate = deadLineDate });
var caheInfo = new TrialCacheInfo() { TrialId = trialInfo.Id, TrialStatusStr = trialInfo.TrialStatusStr, AuthorizationEncrypt = newActivationCode, CriterionTypes = trialInfo.CriterionTypes, AuthorizationDate = trialInfo.AuthorizationDate, CreateUserId = trialInfo.CreateUserId, TrialCode = trialInfo.TrialCode };
await _provider.SetAsync(trialInfo.Id.ToString(), JsonConvert.SerializeObject(caheInfo), TimeSpan.FromDays(7));
}
else
{
return ResponseOutput.NotOk("该授权码与该项目不匹配");
}
return ResponseOutput.Ok();
}
#endregion
#region 患者检查管理
/// <summary>
///检查管理-> 检查Tab 患者列表 (带加入的项目信息 以及检查统计) 原型标注错误,不是检查列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<PatientTrialView>>> GetPatientList(PatientTrialQuery inQuery)
{
var isAdminOrOA = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.Admin || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.OA || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.SuperAdmin;
#region new ok
var query = _patientRepository
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.PatientIdStr.Contains(inQuery.PatientIdStr))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.PatientName.Contains(inQuery.PatientName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.ExperimentName), t => t.SubjectPatientList.Any(t => t.Subject.Trial.ExperimentName.Contains(inQuery.ExperimentName)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAE), t => t.SCPStudyList.Any(t => t.CallingAE == inQuery.CallingAE))
.WhereIf(inQuery.BeginPushTime != null, t => t.LatestPushTime >= inQuery.BeginPushTime)
.WhereIf(inQuery.EndPushTime != null, t => t.LatestPushTime <= inQuery.EndPushTime);
foreach (var calledAE in inQuery.CalledAEList)
{
query = query.Where(t => t.SCPStudyList.Select(c => c.CalledAE).Contains(calledAE));
}
var resultQuery = from patient in query
select new PatientTrialView()
{
PatientId = patient.Id,
PatientBirthDate = patient.PatientBirthDate,
CreateTime = patient.CreateTime,
CalledAEList = patient.SCPStudyList.Select(t => t.CalledAE).Distinct().ToList(),
CallingAEList = patient.SCPStudyList.Select(t => t.CallingAE).Distinct().ToList(),
CreateUserId = patient.CreateUserId,
UpdateTime = patient.UpdateTime,
UpdateUserId = patient.UpdateUserId,
EarliestStudyTime = patient.EarliestStudyTime,
LatestStudyTime = patient.LatestStudyTime,
LatestPushTime = patient.LatestPushTime,
PatientAge = patient.PatientAge,
PatientName = patient.PatientName,
PatientIdStr = patient.PatientIdStr,
PatientSex = patient.PatientSex,
StudyCount = patient.SCPStudyList.Count(),
TrialList = patient.SubjectPatientList.Where(t => isAdminOrOA ? true : t.Subject.Trial.TrialUserList.Any(t => t.UserId == _userInfo.Id)).Select(c => new PatientTrialStatInfo()
{
ExperimentName = c.Subject.Trial.ExperimentName,
VisitCount = c.Subject.SubjectVisitList.Count()
}).ToList(),
};
var pageList = await resultQuery.ToPagedListAsync(inQuery, nameof(PatientQueryView.PatientIdStr));
#endregion
return ResponseOutput.Ok(pageList);
}
/// <summary>
/// 检查管理-> 患者加入项目 初始化勾选列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<PatientJoinTrialInitView>>> GetPatientJoinTrialInitList(PatientJoinTrialInitQuery inQuery)
{
//排除已参与的项目列表
var exceptQuery = _subjectPatientRepository.Where(t => t.PatientId == inQuery.PatientId).Select(t => t.Subject.TrialId);
var trialQuery = _trialRepository.Where(t => t.TrialStatusStr == StaticData.TrialState.TrialOngoing)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Filter), t => t.ResearchProgramNo.Contains(inQuery.Filter) || t.ExperimentName.Contains(inQuery.Filter))
.Where(t => !exceptQuery.Any(c => c == t.Id)).ProjectTo<PatientJoinTrialInitView>(_mapper.ConfigurationProvider);
var pageList = await trialQuery.ToPagedListAsync(inQuery, nameof(PatientJoinTrialInitView.ResearchProgramNo));
return ResponseOutput.Ok(pageList);
}
/// <summary>
/// 检查管理-> 患者加入项目 下拉框勾选列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<List<PatientJoinTrialSelectView>>> GetPatientJoinTrialInitSelectList(PatientJoinTrialInitQuery inQuery)
{
//排除已参与的项目列表
var exceptQuery = _subjectPatientRepository.Where(t => t.PatientId == inQuery.PatientId).Select(t => t.Subject.TrialId);
var trialQuery = _trialRepository.Where(t => t.TrialStatusStr == StaticData.TrialState.TrialOngoing)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Filter), t => t.ResearchProgramNo.Contains(inQuery.Filter) || t.ExperimentName.Contains(inQuery.Filter))
.Where(t => t.TrialUserList.Any(c => c.UserId == _userInfo.Id))
.Where(t => !exceptQuery.Any(c => c == t.Id)).ProjectTo<PatientJoinTrialSelectView>(_mapper.ConfigurationProvider);
var list = trialQuery.ToList();
return ResponseOutput.Ok(list);
}
/// <summary>
/// 检查管理-> 患者已加入的列表(原型有误,应该展示 项目 下的subject 绑定关系)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<PatientJoinedTrialView>>> GetPatientJoinedTrialList(PatientJoinedTrialQuery inQuery)
{
var isAdminOrOA = _userInfo.UserTypeEnumInt == (int)UserTypeEnum.Admin || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.OA || _userInfo.UserTypeEnumInt == (int)UserTypeEnum.SuperAdmin;
var trialQuery = _subjectPatientRepository.Where(t => t.PatientId == inQuery.PatientId)
.Where(t => isAdminOrOA ? true : t.Subject.Trial.TrialUserList.Any(t => t.UserId == _userInfo.Id))
.ProjectTo<PatientJoinedTrialView>(_mapper.ConfigurationProvider);
var pageList = await trialQuery.ToPagedListAsync(inQuery);
return ResponseOutput.Ok(pageList);
}
/// <summary>
/// 检查管理-> 获取患者检查列表(同步影像数据之前的)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<PageOutput<PatientStudySimpleView>> GetPatientStudyList(PatientStudyInfoQuery inQuery)
{
var query = from scpStudy in _studyRepository.Where(t => t.PatientId == inQuery.PatientId)
.WhereIf(inQuery.EarliestStudyTime != null, t => t.StudyTime >= inQuery.EarliestStudyTime)
.WhereIf(inQuery.LatestStudyTime != null, t => t.StudyTime <= inQuery.LatestStudyTime)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Modalities), t => t.Modalities.Contains(inQuery.Modalities))
select new PatientStudySimpleView()
{
Description = scpStudy.Description,
CalledAE = scpStudy.CalledAE,
CallingAE = scpStudy.CallingAE,
InstanceCount = scpStudy.InstanceCount,
Modalities = scpStudy.Modalities,
PatientId = scpStudy.PatientId,
AccessionNumber = scpStudy.AccessionNumber,
SCPStudyId = scpStudy.Id,
SeriesCount = scpStudy.SeriesCount,
StudyTime = scpStudy.StudyTime,
};
var pageList = await query.ToPagedListAsync(inQuery, nameof(PatientStudySimpleView.StudyTime));
return pageList;
}
public async Task<IResponseOutput<List<PatientSeriesDTO>>> GetPatientSeriesList(Guid scpStudyId,
[FromServices] IRepository<SCPSeries> _seriesRepository,
[FromServices] IRepository<SCPInstance> _instanceRepository
)
{
var seriesList = await _seriesRepository.Where(s => s.StudyId == scpStudyId).OrderBy(s => s.SeriesNumber).
ThenBy(s => s.SeriesTime).ThenBy(s => s.CreateTime)
.ProjectTo<PatientSeriesDTO>(_mapper.ConfigurationProvider).ToListAsync();
var instanceList = await _instanceRepository.Where(s => s.StudyId == scpStudyId).OrderBy(t => t.SeriesId).ThenBy(t => t.InstanceNumber)
.ThenBy(s => s.InstanceTime).ThenBy(s => s.CreateTime)
.Select(t => new { t.SeriesId, t.Id, t.Path, t.NumberOfFrames, t.InstanceNumber }).ToListAsync();//.GroupBy(u => u.SeriesId);
foreach (var series in seriesList)
{
series.InstanceInfoList = instanceList.Where(t => t.SeriesId == series.Id).OrderBy(t => t.InstanceNumber).Select(k =>
new InstanceBasicInfo()
{
Id = k.Id,
NumberOfFrames = k.NumberOfFrames,
HtmlPath = string.Empty,
Path = k.Path,
InstanceNumber = k.InstanceNumber,
}).ToList();
}
var study = await _studyRepository.FirstOrDefaultAsync(t => t.Id == scpStudyId);
return ResponseOutput.Ok(seriesList, study);
}
[UnitOfWork]
[HttpDelete]
public async Task<IResponseOutput> DeletePatientStudy(Guid patiendId, Guid scpStudyId,
[FromServices] IRepository<SCPSeries> _SeriesRepository,
[FromServices] IRepository<SCPInstance> _instanceRepository)
{
if (_studySubjectVisitRepository.Any(t => t.SCPStudyId == scpStudyId && t.StudyId != null))
{
return ResponseOutput.NotOk("该检查已绑定某项目下受试者访视(不一定是你所创建的项目)并已提交生成任务,不允许删除该检查");
}
else
{
await _subjectPatientRepository.DeleteFromQueryAsync(t => t.PatientId == patiendId);
await _studySubjectVisitRepository.DeleteFromQueryAsync(t => t.SCPStudyId == scpStudyId);
}
await _studyRepository.BatchDeleteNoTrackingAsync(t => t.Id == scpStudyId);
await _SeriesRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == scpStudyId);
await _instanceRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == scpStudyId);
return ResponseOutput.Ok();
}
/// <summary>
/// 清除该患者绑定的受试者的所有的数据、(subject subjectVisit visitTask dicom)
/// </summary>
/// <param name="patientId"></param>
/// <returns></returns>
[UnitOfWork]
public async Task<IResponseOutput> DeletePatientStudyAllData(Guid patientId,
[FromServices] IRepository<VisitTask> _visitTaskRepository,
[FromServices] IRepository<SCPSeries> _SeriesRepository,
[FromServices] IRepository<SCPInstance> _instanceRepository,
[FromServices] IRepository<DicomStudy> _dicomStudyRepository,
[FromServices] IRepository<DicomSeries> _dicomSeriesRepository,
[FromServices] IRepository<DicomInstance> _dicomInstanceRepository,
[FromServices] IOSSService oSSService)
{
//清理自己管理的项目的数据
var subjectPatientList = await _subjectPatientRepository.Where(t => t.PatientId == patientId && t.Subject.Trial.TrialUserList.Any(t => t.UserId == _userInfo.Id))
.Select(t => new { t.SubjectId, StudyInstanceUidList = t.Patient.SCPStudyList.Select(t => t.StudyInstanceUid).ToList() }).ToListAsync();
if (_studyRepository.Any(t => t.IsUploadFinished == false && t.PatientId == patientId))
{
return ResponseOutput.NotOk("当前患者有检查正在上传,不允许清理数据");
}
foreach (var item in subjectPatientList)
{
var subjectId = item.SubjectId;
await _subjectRepository.BatchDeleteNoTrackingAsync(t => t.Id == subjectId);
await _studySubjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
await _subjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
await _visitTaskRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
await _dicomStudyRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
await _dicomSeriesRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
await _dicomInstanceRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
}
var instanceUidList = subjectPatientList.SelectMany(t => t.StudyInstanceUidList).Distinct().ToList();
foreach (var studyInstanceUid in instanceUidList)
{
{
var ossFolderPath = $"Dicom/{studyInstanceUid}";
await oSSService.DeleteFromPrefix(ossFolderPath);
}
}
var sCPStudyIdList = _studyRepository.Where(t => t.PatientId == patientId).Select(t => t.Id).ToList();
await _patientRepository.BatchDeleteNoTrackingAsync(t => t.Id == patientId);
foreach (var item in sCPStudyIdList)
{
await _studyRepository.BatchDeleteNoTrackingAsync(t => t.Id == item);
await _SeriesRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == item);
await _instanceRepository.BatchDeleteNoTrackingAsync(t => t.StudyId == item);
}
return ResponseOutput.Ok();
}
#endregion
#region 受试者管理
[TrialGlobalLimit("AfterStopCannNotOpt")]
[HttpPost]
public async Task<IResponseOutput<string>> AddOrUpdateSubject([FromBody] AddOrUpdateSubjectCommand subjectCommand)
{
var svlist = new List<SubjectVisit>();
var verifyExp1 = new EntityVerifyExp<Subject>()
{
VerifyExp = u => u.Code == subjectCommand.Code && u.TrialId == subjectCommand.TrialId,
//---已存在具有相关受试者编号的受试者。
VerifyMsg = _localizer["Subject_DuplicateSubjectNum"]
};
Subject? mapedSubject = null;
if (subjectCommand.Id == null) //insert
{
mapedSubject = await _subjectRepository.InsertFromDTOAsync(subjectCommand, false, verifyExp1);
}
else //update
{
mapedSubject = await _subjectRepository.UpdateFromDTOAsync(subjectCommand, false, false, verifyExp1/*, verifyExp2*/);
}
await _subjectRepository.SaveChangesAsync();
return ResponseOutput.Ok(mapedSubject.Id.ToString());
}
/// <summary>
/// 受试者管理-> 受试者列表 (带患者信息,患者信息是数组)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<PatienSubejctView>>> GetPatientSubejctList(PatientSubjectQuery inQuery)
{
var subjectQuery = _subjectRepository.Where(u => u.TrialId == inQuery.TrialId)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Code), t => t.Code.Contains(inQuery.Code))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.ShortName), t => t.ShortName.Contains(inQuery.ShortName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Sex), t => t.Sex.Contains(inQuery.Sex))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.SubjectPatientList.Any(t => t.Patient.PatientIdStr.Contains(inQuery.PatientIdStr)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.SubjectPatientList.Any(t => t.Patient.PatientName.Contains(inQuery.PatientName)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientSex), t => t.SubjectPatientList.Any(t => t.Patient.PatientSex.Contains(inQuery.PatientSex)))
.WhereIf(inQuery.Status != null, t => t.Status == inQuery.Status)
.ProjectTo<PatienSubejctView>(_mapper.ConfigurationProvider);
var pageList = await subjectQuery.ToPagedListAsync(inQuery, nameof(PatienSubejctView.Code));
return ResponseOutput.Ok(pageList);
}
/// <summary>
/// 受试者管理-> 患者列表 subject 列表进入,进行关系绑定初始化列表,排除已绑定的患者和已绑定给其他subject的患者
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<PatientQueryView>>> GetPatientInitList(PatientQuery inQuery)
{
var query = _patientRepository
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.PatientIdStr.Contains(inQuery.PatientIdStr))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.PatientName.Contains(inQuery.PatientName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.CallingAE), t => t.SCPStudyList.Any(t => t.CallingAE == inQuery.CallingAE))
.WhereIf(inQuery.EarliestStudyTime != null, t => t.EarliestStudyTime >= inQuery.EarliestStudyTime)
.WhereIf(inQuery.LatestStudyTime != null, t => t.LatestStudyTime <= inQuery.LatestStudyTime)
//排除该受试者已绑定的患者
.WhereIf(inQuery.SubjectId != null, t => !t.SubjectPatientList.Any(u => u.SubjectId == inQuery.SubjectId))
//排除该项目已绑定的其他患者
.Where(t => !t.SubjectPatientList.Any(c => c.Subject.TrialId == inQuery.TrialId));
foreach (var calledAE in inQuery.CalledAEList)
{
query = query.Where(t => t.SCPStudyList.Select(c => c.CalledAE).Contains(calledAE));
}
var patientQuery = query.ProjectTo<PatientQueryView>(_mapper.ConfigurationProvider);
var pageList = await patientQuery.ToPagedListAsync(inQuery, nameof(PatientQueryView.PatientIdStr));
return ResponseOutput.Ok(pageList);
}
/// <summary>
/// 受试者管理->患者列表 Dicom AE 下拉框数据获取
/// </summary>
/// <returns></returns>
public async Task<List<string>> GetDicomCalledAEList()
{
var list = await _studyRepository.Select(t => t.CalledAE).Distinct().ToListAsync();
return list;
}
public async Task<List<string>> GetDicomCallingAEList()
{
var list = await _studyRepository.Select(t => t.CallingAE).Distinct().ToListAsync();
return list;
}
/// <summary>
///受试者管理-> 患者列表 模糊搜索下拉 选择subject 排除已绑定并提交的
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<SubjectSelectDto>> GetTrialSubejctSelectList(SubjectSelectQuery inQuery)
{
var list = await _subjectRepository.Where(t => t.TrialId == inQuery.TrialId && t.Status == SubjectStatus.OnVisit)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectCode), u => u.Code.Contains(inQuery.SubjectCode))
.WhereIf(inQuery.SubjectId != null, t => t.Id == inQuery.SubjectId)
//.Where(t => !t.SubjectVisitList.SelectMany(t => t.SCPStudySubjectVisitList).Any(c => c.StudyId != null))
.Select(t => new SubjectSelectDto()
{
SubejctId = t.Id,
SubjectCode = t.Code,
Status = t.Status,
Sex = t.Sex,
ShortName = t.ShortName,
Age = t.Age,
BirthDate = t.BirthDate,
PatientList = t.SubjectPatientList.Select(c => new PatienBasicInfo() { PatientId = c.PatientId, PatientIdStr = c.Patient.PatientIdStr }).ToList()
})
.ToListAsync();
return list;
}
#endregion
#region 患者和受试者绑定,生成访视,预先绑定检查和访视
[HttpPost]
public async Task<IResponseOutput> GetVisitStudyVerifyTime(VisitStudyVerifyTimeQuery inQuery)
{
var scpStudyList = await _studySubjectVisitRepository.Where(t => t.TrialId == inQuery.TrialId && t.SubjectId == inQuery.SubjectId && t.SCPStudyId != inQuery.SCPStudyId)
.Select(t => new { SubjectVisitId = t.SubjectVisitId, StudyTime = t.SCPStudy.StudyTime, t.SubjectVisit.SubmitState, t.SubjectVisit.VisitName, VisitNum = t.SubjectVisit.VisitNum, SCPStudyId = t.SCPStudyId })
.ToListAsync();
var result = scpStudyList.GroupBy(t => new { t.VisitName, t.VisitNum, t.SubjectVisitId, t.SubmitState })
.Select(g => new
{
g.Key.SubmitState,
g.Key.VisitNum,
g.Key.VisitName,
g.Key.SubjectVisitId,
VisitMaxStudyTime = g.Max(c => c.StudyTime),
VisitMinStudyTime = g.Min(c => c.StudyTime)
});
return ResponseOutput.Ok(result);
}
public class AuToBindingStudyInfo
{
public Guid SCPStudyId { get; set; }
public DateTime? StudyTime { get; set; }
}
private async Task DealAutoBindingStudyAsync(Guid trialId, Guid subjectId, List<AuToBindingStudyInfo> studyList, decimal? startBindVisitNum = null)
{
studyList = studyList.OrderBy(t => t.StudyTime).ToList();
//自动创建访视 和检查绑定
//1. 查询已存在的访视
var subjectAllVisitList = await _subjectVisitRepository.Where(t => t.SubjectId == subjectId)
.Select(t => new
{
t.SubjectId,
SubjectVisitId = t.Id,
t.SubmitState,
VisitNum = t.VisitNum,
MaxStudyTime = t.SCPStudySubjectVisitList.Max(t => t.SCPStudy.StudyTime),
MinStudyTime = t.SCPStudySubjectVisitList.Min(t => t.SCPStudy.StudyTime)
})
.ToListAsync();
//2、获取项目配置
var trialconfig = _trialRepository.Where(t => t.Id == trialId).Select(t => new { t.BlindBaseLineName, t.BlindFollowUpPrefix }).FirstOrDefault();
//3、 未提交的最小的访视号 从这个访视开始绑定 因为重新开始绑定,所以将访视未提交的状态重置
var subjectMaxVisitNum = startBindVisitNum == null ? subjectAllVisitList.Where(t => t.SubmitState != SubmitStateEnum.Submitted).MinOrDefault(t => t.VisitNum) : startBindVisitNum.Value;
await _subjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.SubjectId == subjectId && t.SubmitState != SubmitStateEnum.Submitted && t.VisitNum > subjectMaxVisitNum, c => new SubjectVisit() { SubmitState = SubmitStateEnum.None });
List<(int VisitCount, Guid SCPStudyId)> visits = new List<(int, Guid)>();
int visitCount = 0;
DateTime? lastVisitTime = null;
foreach (var study in studyList)
{
if (lastVisitTime == null || (study.StudyTime - lastVisitTime.Value).Value.TotalDays >= 15)
{
// 当前时间点与上一个访视时间点间隔大于等于 15 天,需要建立一个新的访视
visitCount++;
visits.Add((visitCount, study.SCPStudyId));
}
else
{
visits.Add((visitCount, study.SCPStudyId));
}
lastVisitTime = study.StudyTime;
}
//4、生成访视 并且绑定
for (int i = 0; i < visitCount; i++)
{
var bindSubjectVisitId = Guid.Empty;
var bindVisitNum = i + subjectMaxVisitNum;
var existSubjectVisit = subjectAllVisitList.FirstOrDefault(t => t.SubjectId == subjectId && t.VisitNum == bindVisitNum);
if (existSubjectVisit == null)
{
bindSubjectVisitId = NewId.NextGuid();
//基线
if (bindVisitNum == 0)
{
await _subjectVisitRepository.AddAsync(new SubjectVisit() { TrialId = trialId, SubjectId = subjectId, VisitName = trialconfig.BlindBaseLineName, VisitNum = bindVisitNum, Id = bindSubjectVisitId, SubmitState = SubmitStateEnum.ToSubmit, IsBaseLine = true });
}
else
{
await _subjectVisitRepository.AddAsync(new SubjectVisit() { TrialId = trialId, SubjectId = subjectId, VisitName = trialconfig.BlindFollowUpPrefix + $" {(int)bindVisitNum}", VisitNum = bindVisitNum, Id = bindSubjectVisitId, SubmitState = SubmitStateEnum.ToSubmit });
}
}
else
{
bindSubjectVisitId = existSubjectVisit.SubjectVisitId;
}
var currentVisitStudyList = visits.Where(t => t.VisitCount == (i + 1)).ToList();
foreach (var item in currentVisitStudyList)
{
//访视状态为未提交才绑定
if (!subjectAllVisitList.Any(t => t.SubjectId == subjectId && t.SubjectVisitId == bindSubjectVisitId && t.SubmitState == SubmitStateEnum.Submitted))
{
var find = await _subjectVisitRepository.FindAsync(bindSubjectVisitId);
find.SubmitState = SubmitStateEnum.ToSubmit;
await _studySubjectVisitRepository.AddAsync(new SCPStudySubjectVisit() { TrialId = trialId, SubjectVisitId = bindSubjectVisitId, SCPStudyId = item.SCPStudyId, SubjectId = subjectId });
}
}
}
await _subjectPatientRepository.SaveChangesAsync();
}
/// <summary>
/// 之前患者和subject已绑定后新来了的检查 可能需要新建访视,或者和已有访视在同一区间,需要自动绑定
/// </summary>
/// <param name="inCommand"></param>
/// <returns></returns>
[HttpPost]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> AutoBindingPatientStudyVisit(AutoBindingPatientStudyVisitCommand inCommand)
{
//找到已绑定患者,但是没绑定检查的 新来的检查->现在换成未提交的
//var query = from scpStudy in _studyRepository.Where(t => !t.SCPStudySubjectVisitList.Any(t => t.TrialId == inCommand.TrialId))
var query = from scpStudy in _studyRepository.Where(t => !t.SCPStudySubjectVisitList.Any(t => t.TrialId == inCommand.TrialId && t.SubjectVisit.SubmitState == SubmitStateEnum.Submitted))
join subjectPatient in _subjectPatientRepository.Where(t => t.Subject.TrialId == inCommand.TrialId)
on scpStudy.PatientId equals subjectPatient.PatientId
select new
{
subjectPatient.SubjectId,
subjectPatient.PatientId,
SCPStudyId = scpStudy.Id,
StudyTime = scpStudy.StudyTime
};
var list = query.ToList();
if (list.Count > 0)
{
//2、获取项目配置
var trialconfig = _trialRepository.Where(t => t.Id == inCommand.TrialId).Select(t => new { t.BlindBaseLineName, t.BlindFollowUpPrefix }).FirstOrDefault();
var subjectIdList = list.Select(t => t.SubjectId).ToList();
var allSubjectVisitList = await _subjectVisitRepository.Where(t => subjectIdList.Contains(t.SubjectId)).Select(t => new { t.SubjectId, SubjectVisitId = t.Id, t.SubmitState, VisitNum = t.VisitNum, MaxStudyTime = t.SCPStudySubjectVisitList.Max(t => t.SCPStudy.StudyTime), MinStudyTime = t.SCPStudySubjectVisitList.Min(t => t.SCPStudy.StudyTime) }).ToListAsync();
foreach (var g in list.GroupBy(t => t.SubjectId))
{
var subjectId = g.Key;
var subjectStudyList = g.ToList();
var subjectVisitList = allSubjectVisitList.Where(t => t.SubjectId == subjectId).ToList();
// 预先处理1 删除未提交的所有绑定的检查记录,所有检查一起考虑绑定
await _studySubjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState != SubmitStateEnum.Submitted);
//预处理2 找到该subjecct 已提交的访视的最大检查时间,绑定的检查时间要比这个时间要大
var maxStudyTime = subjectVisitList.Where(t => t.SubmitState == SubmitStateEnum.Submitted).MaxOrDefault(t => t.MaxStudyTime);
var needDealStudyList = subjectStudyList.WhereIf(maxStudyTime != null, t => t.StudyTime > maxStudyTime).Select(t => new AuToBindingStudyInfo() { SCPStudyId = t.SCPStudyId, StudyTime = t.StudyTime }).ToList();
await DealAutoBindingStudyAsync(inCommand.TrialId, subjectId, needDealStudyList);
}
await _subjectVisitRepository.SaveChangesAsync();
}
return ResponseOutput.Ok();
}
public async Task<IResponseOutput> VerifyTrialSubject(VerifyTrialSubjectCommand inCommand, [FromServices] IRepository<SubjectVisit> _subjectVisitReposiotry)
{
var find = await _subjectRepository.FirstOrDefaultAsync(t => t.TrialId == inCommand.TrialId && t.Code == inCommand.SubjectCode);
if (find != null)
{
return ResponseOutput.NotOk($"项目中已存在编号为“{find.Code}”的受试者,状态为:{(find.Status == SubjectStatus.OnVisit ? "访" : "访")},不允许添加。", ApiResponseCodeEnum.NeedTips);
}
return ResponseOutput.Ok();
}
/// <summary>
/// 建立subject与患者绑定 如果是下拉则传递SubjectId,如果不存在,创建,那么就传递 SubjectCode
///
/// 绑定以后,后台自动创建访视 和检查预先绑定
/// </summary>
/// <param name="inCommand"></param>
/// <returns></returns>
[HttpPost]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> AddSubjectPatientBinding(AddSubjectPatientCommand inCommand, [FromServices] IRepository<SubjectVisit> _subjectVisitReposiotry)
{
var patientInfo = _patientRepository.Where(t => inCommand.PatientIdList.Contains(t.Id)).Select(t => new { t.PatientBirthDate, t.PatientName, t.PatientSex }).FirstOrDefault();
var subjectId = Guid.Empty;
if (inCommand.SubjectId == null)
{
var find = await _subjectRepository.FirstOrDefaultAsync(t => t.TrialId == inCommand.TrialId && t.Code == inCommand.SubjectCode);
if (find == null)
{
subjectId = NewId.NextSequentialGuid();
var subjectName = patientInfo?.PatientName ?? string.Empty;
DateTime date;
DateTime? birthDate = DateTime.TryParse(patientInfo.PatientBirthDate, out date) ? date : null;
var sex = patientInfo.PatientSex?.ToUpper();
// 计算年龄
int? age = null;
if (birthDate != null)
{
var patientAge = DateTime.Now.Year - birthDate.Value.Year;
// 如果生日还未到,年龄减去一岁
if (DateTime.Now < birthDate.Value.AddYears(patientAge))
{
patientAge--;
}
age = patientAge;
}
await _subjectRepository.AddAsync(new Subject() { Id = subjectId, Code = inCommand.SubjectCode, TrialId = inCommand.TrialId, ShortName = subjectName, BirthDate = birthDate, Sex = sex, Age = age });
}
else
{
return ResponseOutput.NotOk($"项目中已存在编号为“{find.Code}”的受试者,状态为:{(find.Status == SubjectStatus.OnVisit ? "访" : "访")},不允许添加。");
//subjectId = find.Id;
}
}
else
{
subjectId = (Guid)inCommand.SubjectId;
}
foreach (var item in inCommand.PatientIdList)
{
if (!_subjectPatientRepository.Any(t => t.PatientId == item && t.SubjectId == subjectId))
{
await _subjectPatientRepository.AddAsync(new SubjectPatient() { PatientId = item, SubjectId = subjectId });
}
}
// 预先处理1 数据库可能有已存在的subject 患者绑定,在这里要一起考虑绑定
var dbPatientIdList = _subjectPatientRepository.Where(t => t.SubjectId == subjectId).Select(t => t.PatientId).ToList();
inCommand.PatientIdList = dbPatientIdList.Union(inCommand.PatientIdList).Distinct().ToList();
// 预先处理2 删除未提交的所有绑定的检查记录,所有检查一起考虑绑定
await _studySubjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState != SubmitStateEnum.Submitted);
//预处理3 找到该subjecct 已提交的访视的最大检查时间,绑定的检查时间要比这个时间要大
var maxStudyTime = _studySubjectVisitRepository.Where(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState == SubmitStateEnum.Submitted)
.MaxOrDefault(t => t.SCPStudy.StudyTime);
// 预处理4 处理需要绑定的检查
//获取 该受试者绑定患者已存在的检查,考虑要生成多少个访视,去除已提交的检查
var studyList = await _studyRepository.Where(t => inCommand.PatientIdList.Contains(t.PatientId)
&& !t.SCPStudySubjectVisitList.Any(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState == SubmitStateEnum.Submitted))
.WhereIf(maxStudyTime != null, t => t.StudyTime > maxStudyTime)
.Select(t => new AuToBindingStudyInfo { SCPStudyId = t.Id, StudyTime = t.StudyTime }).OrderBy(t => t.StudyTime).Distinct().ToListAsync();
await DealAutoBindingStudyAsync(inCommand.TrialId, subjectId, studyList);
return ResponseOutput.Ok(subjectId);
}
/// <summary>
/// 删除 受试者 和患者之间的绑定
/// </summary>
/// <param name="inCommand"></param>
/// <returns></returns>
[HttpDelete]
[UnitOfWork]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> DeleteSubjectPatientBinding(DeleteSubejctPatientCommand inCommand,
[FromServices] IRepository<VisitTask> _visitTaskRepository,
[FromServices] IRepository<DicomStudy> _dicomStudyRepository,
[FromServices] IRepository<DicomSeries> _dicomSeriesRepository,
[FromServices] IRepository<DicomInstance> _dicomInstanceRepository)
{
var subjectId = inCommand.SubjectId;
var patientId = inCommand.PatientId;
var find = await _subjectPatientRepository.FirstOrDefaultAsync(t => t.PatientId == patientId && t.SubjectId == subjectId);
if (find != null)
{
//该患者检查 没有绑定提交的
if (!_studySubjectVisitRepository.Any(t => t.SubjectId == find.SubjectId && t.SCPStudy.PatientId == patientId && t.StudyId != null))
{
await _subjectPatientRepository.DeleteAsync(find);
await _studySubjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == find.SubjectId && t.SCPStudy.PatientId == patientId);
await _subjectPatientRepository.SaveChangesAsync();
//触发其余访视检查自动绑定
// 预先处理1 数据库可能有已存在的subject 患者绑定,在这里要一起考虑绑定
var dbPatientIdList = _subjectPatientRepository.Where(t => t.SubjectId == subjectId).Select(t => t.PatientId).ToList();
// 预先处理2 删除未提交的所有绑定的检查记录,所有检查一起考虑绑定
await _studySubjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState != SubmitStateEnum.Submitted);
//预处理3 找到该subjecct 已提交的访视的最大检查时间,绑定的检查时间要比这个时间要大
var maxStudyTime = _studySubjectVisitRepository.Where(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState == SubmitStateEnum.Submitted)
.MaxOrDefault(t => t.SCPStudy.StudyTime);
// 预处理4 处理需要绑定的检查
//获取 该受试者绑定患者已存在的检查,考虑要生成多少个访视,去除已提交的检查
var studyList = await _studyRepository.Where(t => dbPatientIdList.Contains(t.PatientId)
&& !t.SCPStudySubjectVisitList.Any(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState == SubmitStateEnum.Submitted))
.WhereIf(maxStudyTime != null, t => t.StudyTime > maxStudyTime)
.Select(t => new AuToBindingStudyInfo { SCPStudyId = t.Id, StudyTime = t.StudyTime }).OrderBy(t => t.StudyTime).Distinct().ToListAsync();
await DealAutoBindingStudyAsync(inCommand.TrialId, subjectId, studyList);
}
else if (_studySubjectVisitRepository.Any(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState == SubmitStateEnum.Submitted))
{
return ResponseOutput.NotOk(_localizer["该受试者有访视已提交,不允许解除受试者和该患者的绑定关系"]);
}
//当前是最后移除的患者
if (!_subjectPatientRepository.Any(t => t.SubjectId == subjectId && t.PatientId != patientId))
{
#region 设置了末次访视,然后一起删除会报 级联错误
////q1:单独查询删除
//await _subjectRepository.DeleteFromQueryAsync(t => t.Id == subjectId);
//await _subjectVisitRepository.DeleteFromQueryAsync(t => t.SubjectId == subjectId);
//q2 一起查询删除 没区别,一样报错
//var subject = await _subjectRepository.Where(t => t.Id == subjectId, true).Include(t => t.SubjectVisitList).FirstOrDefaultAsync();
//await _subjectRepository.DeleteAsync(subject);
#endregion
//q3 设置导航属性为null 依旧不行
//var subject = await _subjectRepository.Where(t => t.Id == subjectId, true).Include(t => t.SubjectVisitList).FirstOrDefaultAsync();
//subject.FinalSubjectVisit = null;
//subject.FinalSubjectVisitId = null;
//foreach (var item in subject.SubjectVisitList)
//{
// item.SubjectId = Guid.Empty;
// item.Subject = null;
//}
//await _subjectRepository.DeleteAsync(subject);
await _subjectVisitRepository.DeleteFromQueryAsync(t => t.SubjectId == subjectId, true);
await _subjectRepository.DeleteFromQueryAsync(t => t.Id == subjectId);
}
await _subjectPatientRepository.SaveChangesAsync();
////暂时删除访视 上线删除
//await _subjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
//await _visitTaskRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
//await _dicomStudyRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
//await _dicomSeriesRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
//await _dicomInstanceRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
}
return ResponseOutput.Ok();
}
/// <summary>
/// 患者检查 与SubjectVisit 的绑定
/// </summary>
/// <param name="inCommandList"></param>
/// <returns></returns>
[HttpPost]
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
[Obsolete]
public async Task<IResponseOutput> AddSubjectPatientStudyBinding(List<AddSubjectPatientStudyVisitCommand> inCommandList)
{
var subjectId = inCommandList.First().SubjectId;
//查询数据库所有的绑定,然后将修改的绑定更改过去,验证是否符合要求
var allSubjectVisitList = _subjectVisitRepository.Where(t => t.SubjectId == subjectId).Select(t => new { SubjectVisitId = t.Id, t.VisitNum }).ToList();
var allStudyList = await _studySubjectVisitRepository.Where(t => t.SubjectId == subjectId).Select(t => new VerifyVisitStudyDTO() { SubjectVisitId = t.SubjectVisitId, StudyTime = t.SCPStudy.StudyTime, VisitNum = t.SubjectVisit.VisitNum, SCPStudyId = t.SCPStudyId }).ToListAsync();
foreach (var item in inCommandList)
{
var find = allStudyList.Where(t => t.SCPStudyId == item.SCPStudyId).FirstOrDefault();
if (find != null)
{
find.SubjectVisitId = item.SubjectVisitId;
find.VisitNum = allSubjectVisitList.Where(t => t.SubjectVisitId == item.SubjectVisitId).FirstOrDefault().VisitNum;
}
}
foreach (var item in inCommandList)
{
var currentVisitStudyList = allStudyList.Where(t => t.SubjectVisitId == item.SubjectVisitId).OrderBy(t => t.StudyTime).ToList();
var currentVisitMaxTimeStudy = currentVisitStudyList.LastOrDefault();
if (currentVisitMaxTimeStudy != null)
{
var currentVisitMaxStudyTime = currentVisitMaxTimeStudy.StudyTime;
if (allStudyList.Where(t => t.VisitNum < currentVisitMaxTimeStudy.VisitNum).Any(t => t.StudyTime > currentVisitMaxStudyTime))
{
return ResponseOutput.NotOk(_localizer["当前提交的访视中,前序访视的检查时间比当前绑定访视的检查时间要大,请核查!"]);
}
if (allStudyList.Where(t => t.VisitNum > currentVisitMaxTimeStudy.VisitNum).Any(t => t.StudyTime < currentVisitMaxStudyTime))
{
return ResponseOutput.NotOk(_localizer["当前提交的访视中,后序访视的检查时间比当前绑定访视的检查时间要小,请核查!"]);
}
}
}
var studyIdList = inCommandList.Select(t => t.SCPStudyId).ToList();
await _studySubjectVisitRepository.BatchDeleteNoTrackingAsync(t => studyIdList.Contains(t.SCPStudyId));
foreach (var item in inCommandList)
{
var sv = await _subjectVisitRepository.FindAsync(item.SubjectVisitId);
sv.SubmitState = SubmitStateEnum.ToSubmit;
await _studySubjectVisitRepository.AddAsync(new SCPStudySubjectVisit() { TrialId = item.TrialId, SCPStudyId = item.SCPStudyId, SubjectVisitId = item.SubjectVisitId, SubjectId = item.SubjectId });
}
await _studySubjectVisitRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
/// <summary>
/// 修改 访视 和检查的绑定关系 IsAdd 区分添加 还是移除
/// </summary>
/// <param name="inCommand"></param>
/// <returns></returns>
[TrialGlobalLimit("AfterStopCannNotOpt")]
[UnitOfWork]
public async Task<IResponseOutput> UpdateSubjectVisitStudyBinding(UpdateSubjectVisitStudyBindingCommand inCommand)
{
var subjectId = inCommand.SubjectId;
var subjectVisitId = inCommand.SubjectVisitId;
if (_subjectRepository.Any(t => t.Id == subjectId && t.Status == SubjectStatus.EndOfVisit))
{
return ResponseOutput.NotOk(_localizer["受试者状态为访视结束,不允许绑定访视和检查"]);
}
var subjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == subjectVisitId);
if (inCommand.IsAdd)
{
//找到所有访视的检查
var allStudyList = await _studySubjectVisitRepository.Where(t => t.SubjectId == subjectId).Select(t => new VerifyVisitStudyDTO() { SubjectVisitId = t.SubjectVisitId, StudyTime = t.SCPStudy.StudyTime, VisitNum = t.SubjectVisit.VisitNum, SCPStudyId = t.SCPStudyId }).ToListAsync();
var bindVisit = _subjectVisitRepository.Where(t => t.Id == subjectVisitId).Select(t => new { SubjectVisitId = t.Id, t.VisitNum, SubjectCode = t.Subject.Code }).FirstOrDefault();
var bindStudy = _studyRepository.Where(t => t.Id == inCommand.SCPStudyId).Select(t => new { SCPStudyId = t.Id, t.StudyTime }).FirstOrDefault();
//是否之前和其他访视绑定
var findStudy = allStudyList.FirstOrDefault(t => t.SCPStudyId == inCommand.SCPStudyId);
if (findStudy != null)
{
findStudy.SubjectVisitId = bindVisit.SubjectVisitId;
findStudy.VisitNum = bindVisit.VisitNum;
}
else
{
//新的检查
allStudyList.Add(new VerifyVisitStudyDTO() { SCPStudyId = inCommand.SCPStudyId, SubjectVisitId = bindVisit.SubjectVisitId, VisitNum = bindVisit.VisitNum, StudyTime = bindStudy.StudyTime });
}
var visitOrderStudyList = allStudyList.OrderBy(t => t.VisitNum).ThenBy(t => t.StudyTime).ToList();
var studyTimeOrderList = visitOrderStudyList.OrderBy(t => t.StudyTime).ToList();
bool arraysEqual = visitOrderStudyList.SequenceEqual(studyTimeOrderList);
if (!arraysEqual)
{
return ResponseOutput.NotOk(_localizer[$"{bindVisit.SubjectCode}所提交的访视中的检查时间,不符合后续访视的检查时间比前序检查的时间大的要求"]);
}
//如果该检查之前和其他访视绑定,那么更新绑定的访视就可以
var otherFind = await _studySubjectVisitRepository.FirstOrDefaultAsync(t => t.SCPStudyId == inCommand.SCPStudyId && t.SubjectId == inCommand.SubjectId);
if (otherFind == null)
{
await _studySubjectVisitRepository.AddAsync(new SCPStudySubjectVisit() { TrialId = inCommand.TrialId, SCPStudyId = inCommand.SCPStudyId, SubjectVisitId = subjectVisitId, SubjectId = inCommand.SubjectId });
}
else
{
//为了稽查 先删除 再添加
await _studySubjectVisitRepository.DeleteAsync(otherFind);
if (!_studySubjectVisitRepository.Any(t => t.SubjectVisitId == otherFind.SubjectVisitId && t.SCPStudyId != inCommand.SCPStudyId))
{
var updateVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == otherFind.SubjectVisitId);
updateVisit.SubmitState = SubmitStateEnum.None;
}
//otherFind.SubjectVisitId = inCommand.SubjectVisitId;
await _studySubjectVisitRepository.AddAsync(new SCPStudySubjectVisit() { TrialId = inCommand.TrialId, SCPStudyId = inCommand.SCPStudyId, SubjectVisitId = subjectVisitId, SubjectId = inCommand.SubjectId });
}
subjectVisit.SubmitState = SubmitStateEnum.ToSubmit;
await _studySubjectVisitRepository.SaveChangesAsync();
#region 处理自动绑定
//触发自动绑定后续检查和访视的绑定关系
//预先处理1找到所有未提交的检查访视绑定
var studyList = await _studySubjectVisitRepository.Where(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState != SubmitStateEnum.Submitted)
.Select(t => new VerifyVisitStudyDTO() { SubjectVisitId = t.SubjectVisitId, StudyTime = t.SCPStudy.StudyTime, VisitNum = t.SubjectVisit.VisitNum, SCPStudyId = t.SCPStudyId }).ToListAsync();
var needDealStudyList = studyList.Where(t => t.VisitNum > subjectVisit.VisitNum).Select(t => new AuToBindingStudyInfo() { SCPStudyId = t.SCPStudyId, StudyTime = t.StudyTime }).ToList();
if (needDealStudyList.Count > 0)
{
//没有该访视的检查
var findVisitStudy = studyList.Where(t => t.SubjectVisitId == subjectVisitId).FirstOrDefault();
//就从当前访视开始绑定,否则就从下一个访视开始绑定
var startBindingVisitNum = findVisitStudy == null ? subjectVisit.VisitNum : subjectVisit.VisitNum + 1;
// 预先处理2 删除未提交的所有绑定的检查记录,所有检查一起考虑绑定
await _studySubjectVisitRepository.DeleteFromQueryAsync(t => t.SubjectId == subjectId && t.SubjectVisit.VisitNum >= startBindingVisitNum);
await DealAutoBindingStudyAsync(inCommand.TrialId, subjectId, needDealStudyList, startBindingVisitNum);
}
#endregion
}
else
{
var find = await _studySubjectVisitRepository.FirstOrDefaultAsync(t => t.SCPStudyId == inCommand.SCPStudyId && t.SubjectVisitId == subjectVisitId);
await _studySubjectVisitRepository.DeleteAsync(find);
if (!_studySubjectVisitRepository.Any(t => t.SubjectVisitId == subjectVisitId && t.SCPStudyId != find.SCPStudyId))
{
subjectVisit.SubmitState = SubmitStateEnum.None;
}
await _studySubjectVisitRepository.SaveChangesAsync();
//预处理1 找到该subjecct 已提交的访视的最大检查时间,绑定的检查时间要比这个时间要大
var maxStudyTime = _subjectVisitRepository.Where(t => t.SubjectId == subjectId && t.SubmitState == SubmitStateEnum.Submitted).SelectMany(t => t.SCPStudySubjectVisitList).MaxOrDefault(t => t.SCPStudy.StudyTime);
//预先处理2找到所有未提交的检查访视绑定 大于当前访视
var studyList = await _studySubjectVisitRepository.Where(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState != SubmitStateEnum.Submitted && t.SubjectVisit.VisitNum > subjectVisit.VisitNum)
.WhereIf(maxStudyTime != null, t => t.SCPStudy.StudyTime > maxStudyTime)
.Select(t => new AuToBindingStudyInfo() { StudyTime = t.SCPStudy.StudyTime, SCPStudyId = t.SCPStudyId }).Distinct().ToListAsync();
if (studyList.Count > 0)
{
//预处理3 删除所有未提交的绑定关系 所有检查一起考虑绑定 排除当前访视
await _studySubjectVisitRepository.DeleteFromQueryAsync(t => t.SubjectId == subjectId && t.SubjectVisit.SubmitState != SubmitStateEnum.Submitted && t.SubjectVisit.VisitNum > subjectVisit.VisitNum);
//没有从当前访视开始绑定,否则就从下一个访视开始绑定
var startBindingVisitNum = !_studySubjectVisitRepository.Any(t => t.SubjectVisitId == subjectVisitId) ? subjectVisit.VisitNum : subjectVisit.VisitNum + 1;
await DealAutoBindingStudyAsync(inCommand.TrialId, subjectId, studyList, startBindingVisitNum);
}
}
return ResponseOutput.Ok();
}
/// <summary>
/// 提交 患者检查和访视的绑定
/// </summary>
/// <param name="inCommand"></param>
/// <returns></returns>
[HttpPost]
[UnitOfWork]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> SubmitVisitStudyBinding(SubmitVisitStudyBindingCommand inCommand,
[FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig,
[FromServices] IRepository _repository
)
{
//防止访视重复
inCommand.SubjectVisitIdList = inCommand.SubjectVisitIdList.Distinct().ToList();
//确认当前提交的最大的访视之前所有的访视都已提交,并且没有漏的
var curentMaxNum = await _subjectVisitRepository.Where(t => inCommand.SubjectVisitIdList.Contains(t.Id)).Select(t => t.VisitNum).MaxAsync();
var allVisitList = _subjectVisitRepository.Where(t => t.TrialId == inCommand.TrialId && t.SubjectId == inCommand.SubjectId && t.VisitNum <= curentMaxNum).Select(t => new { SubjectVisitId = t.Id, t.Subject.Status, t.VisitNum, t.SubmitState }).OrderBy(t => t.VisitNum).ToList();
//批量提交
if (inCommand.SubjectVisitIdList.Count > 1)
{
if (allVisitList.Where(t => t.SubmitState != SubmitStateEnum.Submitted).Count() != inCommand.SubjectVisitIdList.Count())
{
return ResponseOutput.NotOk(_localizer["当前批量提交的访视中间有遗漏的访视或者前序有访视未提交"]);
}
}
else
{
if (allVisitList.Any(t => t.VisitNum < curentMaxNum && t.SubmitState != SubmitStateEnum.Submitted))
{
return ResponseOutput.NotOk(_localizer["前序有访视未提交,请先提交前序访视"]);
}
}
if (allVisitList.Any(t => t.Status == SubjectStatus.EndOfVisit))
{
return ResponseOutput.NotOk(_localizer["受试者状态为访视结束,不允许提交访视生成任务"]);
}
var list = await _studySubjectVisitRepository.Where(t => inCommand.SubjectVisitIdList.Contains(t.SubjectVisitId)).Select(t => new { t.SCPStudyId, t.SCPStudy.PatientId, t.SubjectVisitId, t.SubjectVisit.VisitNum, t.SubjectVisit.SubjectId, SubjectCode = t.SubjectVisit.Subject.Code, t.SubjectVisit.TrialId, t.SCPStudy.StudyTime, t.StudyId, t.SCPStudy.IsUploadFinished }).OrderBy(t => t.StudyTime).ToListAsync();
if (list.Any(t => t.StudyId != null))
{
return ResponseOutput.NotOk(_localizer["有访视和检查处于已绑定关系,不允许再次提交绑定"]);
}
if (list.Any(t => t.IsUploadFinished == false))
{
return ResponseOutput.NotOk(_localizer["有访视检查正在传输中,不允许提交"]);
}
//判断每个subject 批量提交的是否符合时间要求
foreach (var g in list.GroupBy(t => new { t.SubjectId, t.SubjectCode }))
{
var visitOrderStudyList = g.OrderBy(t => t.VisitNum).ThenBy(t => t.StudyTime).ToList();
var studyTimeOrderList = visitOrderStudyList.OrderBy(t => t.StudyTime).ToList();
bool arraysEqual = visitOrderStudyList.SequenceEqual(studyTimeOrderList);
if (!arraysEqual)
{
return ResponseOutput.NotOk(_localizer[$"{g.Key.SubjectCode}所提交的访视中的检查时间,不符合后续访视的检查时间比前序检查的时间大的要求"]);
}
if (DateTime.Now < studyTimeOrderList.Max(t => t.StudyTime))
{
return ResponseOutput.NotOk(_localizer[$"您当前修改了服务器时间,试图绕过软件授权,请恢复服务器时间,并联系授权方授权才可进行操作"]);
}
}
var trialConfig = await _trialRepository.Where(t => t.Id == inCommand.TrialId).Select(t => new { t.IsEnrollementQualificationConfirm, t.IsPDProgressView, t.AuthorizationEncrypt }).FirstOrDefaultAsync();
//var decodedText = Cryptography.DecryptString(trialConfig.AuthorizationEncrypt, _basicSystemConfigConfig.CurrentValue.AESKey, "Trial_AuthorizationEncrypt");
//var authInfo = JsonConvert.DeserializeObject<TrialAuthorizationInfo>(decodedText);
var @lock = _distributedLockProvider.CreateLock($"StudyCode");
using (await @lock.AcquireAsync())
{
var dbStudyCodeIntMax = _repository.Where<DicomStudy>(s => s.TrialId == inCommand.TrialId).Select(t => t.Code).DefaultIfEmpty().Max();
int currentNextCodeInt = dbStudyCodeIntMax + 1;
foreach (var item in list)
{
//提交的访视下没有检查
if (!_studySubjectVisitRepository.Any(t => t.SubjectVisitId == item.SubjectVisitId))
{
return ResponseOutput.NotOk(_localizer["提交的访视下必须有影像检查!"]);
}
var dbSubjectVisit = await _subjectVisitRepository.FirstOrDefaultAsync(t => t.Id == item.SubjectVisitId);
//处理脏数据,可能之前的绑定的数据状态是待上传,但是已经绑定了检查
if (dbSubjectVisit.SubmitState == SubmitStateEnum.ToSubmit || dbSubjectVisit.SubmitState == SubmitStateEnum.None)
{
dbSubjectVisit.SubmitState = SubmitStateEnum.Submitted;
dbSubjectVisit.SubmitTime = DateTime.Now;
dbSubjectVisit.SubmitUserId = _userInfo.Id;
//维护统一状态
//dbSubjectVisit.ReadingStatus = ReadingStatusEnum.TaskAllocate;
dbSubjectVisit.AuditState = AuditStateEnum.QCPassed;
dbSubjectVisit.CheckState = CheckStateEnum.CVPassed;
dbSubjectVisit.IsEnrollmentConfirm = dbSubjectVisit.IsBaseLine ? trialConfig.IsEnrollementQualificationConfirm : false;
dbSubjectVisit.PDState = trialConfig.IsPDProgressView ? PDStateEnum.PDProgress : PDStateEnum.None;
}
var find = _studyRepository.Where(t => t.Id == item.SCPStudyId).Include(t => t.SeriesList).Include(t => t.InstanceList).FirstOrDefault();
if (find != null)
{
//重新算Id
Guid studyId = IdentifierHelper.CreateGuid(item.TrialId.ToString(), find.StudyInstanceUid);
find.Id = studyId;
var newStuty = _mapper.Map<DicomStudy>(find);
await _repository.AddAsync(newStuty);
//newStuty.Id = NewId.NextSequentialGuid();
newStuty.SeqId = NewId.NextSequentialGuid();
newStuty.Code = currentNextCodeInt;
newStuty.StudyCode = AppSettings.GetCodeStr(currentNextCodeInt, nameof(DicomStudy));
newStuty.TrialId = item.TrialId;
newStuty.SubjectId = item.SubjectId;
newStuty.SubjectVisitId = item.SubjectVisitId;
var newSeriesList = _mapper.Map<List<DicomSeries>>(find.SeriesList);
foreach (var series in newSeriesList)
{
Guid seriesId = IdentifierHelper.CreateGuid(item.TrialId.ToString(), find.StudyInstanceUid, series.SeriesInstanceUid);
//重新算Id
series.Id = seriesId;
series.StudyId = newStuty.Id;
series.SeqId = NewId.NextSequentialGuid();
series.TrialId = item.TrialId;
series.SubjectId = item.SubjectId;
series.SubjectVisitId = item.SubjectVisitId;
}
await _repository.AddRangeAsync(newSeriesList);
var newInstanceList = _mapper.Map<List<DicomInstance>>(find.InstanceList);
foreach (var instance in newInstanceList)
{
Guid seriesId = IdentifierHelper.CreateGuid(item.TrialId.ToString(), find.StudyInstanceUid, instance.SeriesInstanceUid);
Guid instanceId = IdentifierHelper.CreateGuid(item.TrialId.ToString(), find.StudyInstanceUid, instance.SeriesInstanceUid, instance.SopInstanceUid);
//重新算Id
instance.Id = instanceId;
instance.SeriesId = seriesId;
instance.StudyId = newStuty.Id;
instance.SeqId = NewId.NextSequentialGuid();
instance.TrialId = item.TrialId;
instance.SubjectId = item.SubjectId;
instance.SubjectVisitId = item.SubjectVisitId;
}
await _repository.AddRangeAsync(newInstanceList);
}
currentNextCodeInt++;
await _studySubjectVisitRepository.BatchUpdateNoTrackingAsync(t => t.SubjectVisitId == item.SubjectVisitId && t.SCPStudyId == item.SCPStudyId, u => new SCPStudySubjectVisit() { StudyId = find.Id });
await _subjectPatientRepository.BatchUpdateNoTrackingAsync(t => t.SubjectId == item.SubjectId && t.PatientId == item.PatientId, u => new SubjectPatient() { IsBinded = true });
}
}
await _studySubjectVisitRepository.SaveChangesAsync();
return ResponseOutput.Ok();
}
#endregion
#region 访视基本管理
/// <summary>
/// 绑定访视 初始化患者检查列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<PatientStudySelectDto>> GetVisitPatientStudyList(PatientStudyQuery inQuery)
{
var patientQuery = from scpStudy in _studyRepository
.Where(t => inQuery.PatientIdList.Contains(t.PatientId))
.WhereIf(inQuery.EarliestStudyTime != null, t => t.StudyTime >= inQuery.EarliestStudyTime)
.WhereIf(inQuery.LatestStudyTime != null, t => t.StudyTime <= inQuery.LatestStudyTime)
join scpStudySubjectVisit in _studySubjectVisitRepository.Where(t => t.SubjectVisit.TrialId == inQuery.TrialId) on scpStudy.Id equals scpStudySubjectVisit.SCPStudyId into cc
from scpStudySubjectVisit in cc.DefaultIfEmpty()
select new PatientStudySelectDto()
{
Description = scpStudy.Description,
CalledAE = scpStudy.CalledAE,
InstanceCount = scpStudy.InstanceCount,
Modalities = scpStudy.Modalities,
PatientId = scpStudy.Patient.Id,
PatientIdStr = scpStudy.PatientIdStr,
PatientAge = scpStudy.PatientAge,
PatientBirthDate = scpStudy.PatientBirthDate,
PatientSex = scpStudy.PatientSex,
PatientName = scpStudy.PatientName,
SCPStudyId = scpStudy.Id,
SeriesCount = scpStudy.SeriesCount,
StudyTime = scpStudy.StudyTime,
CallingAE = scpStudy.CallingAE,
SubmitState = scpStudySubjectVisit.SubjectVisit.SubmitState,
SubjectVisitId = scpStudySubjectVisit.SubjectVisitId
}
;
var sortField = string.IsNullOrWhiteSpace(inQuery.SortField) ? nameof(VisitPatientStudyView.StudyTime) : inQuery.SortField;
var orderQuery = inQuery.Asc ? patientQuery.OrderBy(sortField) : patientQuery.OrderBy(sortField + " desc");
var list = await orderQuery.ToListAsync();
return list;
}
/// <summary>
/// 访视管理- 获取subject 已存在的访视列表 ,同时获取项目访视的配置 在otherData里
/// </summary>
/// <param name="inQuery"></param>
/// <param name="_subjectVisitReposiotry"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput> GetSubjectVisitSelectList(SubjectVisitSelectQuery inQuery, [FromServices] IRepository<SubjectVisit> _subjectVisitReposiotry)
{
var scpStudyList = await _studySubjectVisitRepository.Where(t => t.TrialId == inQuery.TrialId && t.SubjectId == inQuery.SubjectId && t.SCPStudyId != inQuery.SCPStudyId)
.Select(t => new { t.SubjectVisitId, StudyTime = t.SCPStudy.StudyTime })
.ToListAsync();
var result = scpStudyList.GroupBy(t => t.SubjectVisitId)
.Select(g => new
{
SubejctVisitId = g.Key,
VisitMaxStudyTime = g.Max(c => c.StudyTime),
VisitMinStudyTime = g.Min(c => c.StudyTime)
}).ToList();
var list = _subjectVisitReposiotry.Where(t => t.SubjectId == inQuery.SubjectId).ProjectTo<SubjectVisitSelectDto>(_mapper.ConfigurationProvider).ToList();
foreach (var item in list)
{
item.VisitMaxStudyTime = result.Where(t => t.SubejctVisitId == item.Id).FirstOrDefault()?.VisitMaxStudyTime;
item.VisitMinStudyTime = result.Where(t => t.SubejctVisitId == item.Id).FirstOrDefault()?.VisitMinStudyTime;
}
var trialconfig = _trialRepository.Where(t => t.Id == inQuery.TrialId).Select(t => new { t.BlindBaseLineName, t.BlindFollowUpPrefix }).FirstOrDefault();
return ResponseOutput.Ok(list, trialconfig);
}
/// <summary>
/// 添加或者更新受试者访视
/// </summary>
/// <param name="incommand"></param>
/// <param name="_subjectVisitReposiotry"></param>
/// <returns></returns>
[HttpPost]
[TrialGlobalLimit("AfterStopCannNotOpt")]
public async Task<IResponseOutput> AddOrUpdateSubjectVisit(AddOrUpdateSubjectVisitCommand incommand, [FromServices] IRepository<SubjectVisit> _subjectVisitReposiotry)
{
//var verifyExp1 = new EntityVerifyExp<SubjectVisit>()
//{
// VerifyExp = t => t.VisitNum == incommand.VisitNum && t.SubjectId == incommand.SubjectId,
// //---该受试者的访视计划中已经包含一个具有相同访视号的访视。
// VerifyMsg = _localizer["Visit_DuplicateVisitNo"]
//};
//var verifyExp3 = new EntityVerifyExp<SubjectVisit>()
//{
// VerifyExp = t => t.SubjectId == incommand.SubjectId && t.VisitName == incommand.VisitName,
// //---该受试者的访视计划中已经包含一个具有相同访视名称的访视。
// VerifyMsg = _localizer["Visit_DuplicateVisitName"]
//};
var find = _subjectVisitRepository.Where(t => t.TrialId == incommand.TrialId && t.SubjectId == incommand.SubjectId && t.VisitNum == incommand.VisitNum && t.VisitName == incommand.VisitName).FirstOrDefault();
if (find != null)
{
return ResponseOutput.Ok(find.Id);
}
else
{
var entity = await _subjectVisitReposiotry.InsertOrUpdateAsync(incommand, true);
return ResponseOutput.Ok(entity.Id);
}
}
/// <summary>
/// 前端利用组件打成压缩包,后端返回路径和压缩包的信息
/// </summary>
/// <param name="subjectId"></param>
/// <returns></returns>
[HttpGet("{subjectId:guid}/{subjectVisitId:guid}")]
public async Task<IResponseOutput> GetSubjectImageZipInfo(Guid subjectId, Guid subjectVisitId)
{
//var patientQuery = from subject in _subjectRepository.Where(t => t.Id == subjectId)
// select new
// {
// SubjectCode = subject.Code,
// PatientList = subject.SubjectPatientList.Select(c => new
// {
// c.Patient.PatientIdStr,
// c.Patient.PatientName,
// StudyList = c.Patient.SCPStudyList.Select(u => new
// {
// u.StudyTime,
// SeriesList = u.SeriesList.Select(z => new
// {
// z.Modality,
// InstancePathList = z.SCPInstanceList.Select(k => new
// {
// k.Path
// })
// })
// })
// })
// };
var subject_visit_studyQuery = from subject in _subjectRepository.Where(t => t.Id == subjectId)
select new
{
SubjectCode = subject.Code,
PatientList = subject.SubjectPatientList.Select(c => new
{
c.Patient.PatientIdStr,
c.Patient.PatientName
}).ToList(),
VisitList = subject.SubjectVisitList.Where(t => t.Id == subjectVisitId)
.Select(z => new
{
z.VisitName,
StudyList = z.StudyList.Select(u => new
{
u.PatientIdStr,
u.StudyTime,
u.StudyCode,
SeriesList = u.SeriesList.Select(z => new
{
z.Modality,
InstancePathList = z.DicomInstanceList.Select(k => new
{
k.Path
})
})
})
}),
};
#region subject_patient_visit
//var testquery = from subject in _subjectRepository.Where(t => t.Id == subjectId)
// select new
// {
// SubjectCode = subject.Code,
// PatientList = subject.SubjectPatientList.Select(c => new
// {
// c.Patient.PatientIdStr,
// c.Patient.PatientName,
// VisitList = c.Subject.SubjectVisitList.Select(z => new
// {
// z.VisitName,
// StudyList = z.SCPStudySubjectVisitList.Where(t => t.SCPStudy.PatientId == c.PatientId).Select(u => new
// {
// //u.SCPStudy.PatientId,
// u.SCPStudy.PatientIdStr,
// u.SCPStudy.StudyTime,
// SeriesList = u.SCPStudy.SeriesList.Select(z => new
// {
// z.Modality,
// InstancePathList = z.SCPInstanceList.Select(k => new
// {
// k.Path
// })
// })
// })
// }),
// })
// };
#endregion
//var subjectVisitQuery = from subject in _subjectRepository.Where(t => t.Id == subjectId)
// select new
// {
// SubjectCode = subject.Code,
// VisitList = subject.SubjectVisitList.Select(z => new
// {
// z.VisitName,
// StudyList = z.SCPStudySubjectVisitList.Select(u => new
// {
// u.SCPStudy.PatientId,
// u.SCPStudy.PatientIdStr,
// u.SCPStudy.StudyTime,
// SeriesList = u.SCPStudy.SeriesList.Select(z => new
// {
// z.Modality,
// InstancePathList = z.SCPInstanceList.Select(k => new
// {
// k.Path
// })
// })
// })
// })
// };
var result = subject_visit_studyQuery.FirstOrDefault(); ;
return ResponseOutput.Ok(result);
}
/// <summary>
///访视管理-> 访视列表 (带患者信息,患者信息是数组)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<PatientSubjectVisitView>>> GetPatientSubejctVisitList(PatientSubejctVisitQuery inQuery)
{
var query = _subjectVisitRepository.Where(t => t.TrialId == inQuery.TrialId)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectCode), u => u.Subject.Code.Contains(inQuery.SubjectCode))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectSex), u => u.Subject.Sex.Contains(inQuery.SubjectSex))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectShortName), u => u.Subject.ShortName.Contains(inQuery.SubjectShortName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.VisitName), u => u.VisitName.Contains(inQuery.VisitName))
.WhereIf(inQuery.SubmitState != null, u => u.SubmitState == inQuery.SubmitState)
.WhereIf(inQuery.BeginStudyTime != null, t => t.SCPStudySubjectVisitList.Min(t => t.SCPStudy.StudyTime) >= inQuery.BeginStudyTime)
.WhereIf(inQuery.EndStudyTime != null, t => t.SCPStudySubjectVisitList.Max(t => t.SCPStudy.StudyTime) <= inQuery.EndStudyTime)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientIdStr.Contains(inQuery.PatientIdStr)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientName.Contains(inQuery.PatientName)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientSex), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientSex.Contains(inQuery.PatientSex)))
.Select(t => new PatientSubjectVisitView()
{
PatientList = t.Subject.SubjectPatientList.Select(c => new PatientBasicInfo()
{
PatientId = c.PatientId,
PatientAge = c.Patient.PatientAge,
PatientBirthDate = c.Patient.PatientBirthDate,
PatientIdStr = c.Patient.PatientIdStr,
PatientSex = c.Patient.PatientSex,
PatientName = c.Patient.PatientName,
}).ToList(),
TrialId = t.TrialId,
SubjectId = t.SubjectId,
SubjectVisitId = t.Id,
SubjectAge = t.Subject.Age,
SubjectSex = t.Subject.Sex,
SubjectShortName = t.Subject.ShortName,
SubjectCode = t.Subject.Code,
SubmitState = t.SubmitState,
SubmitTime = t.SubmitTime,
VisitNum = t.VisitNum,
VisitName = t.VisitName,
VisitEarliestStudyTime = t.SCPStudySubjectVisitList.Min(t => t.SCPStudy.StudyTime),
VisitLatestStudyTime = t.SCPStudySubjectVisitList.Max(t => t.SCPStudy.StudyTime)
});
var defalutSortArray = new string[] { nameof(PatientSubjectVisitView.SubjectId), nameof(PatientSubjectVisitView.VisitNum) };
var pageList = await query.ToPagedListAsync(inQuery, defalutSortArray);
return ResponseOutput.Ok(pageList);
}
/// <summary>
///访视管理-> 获取当前访视 已绑定的患者检查 (从访视列表 进入修改绑定)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<VisitPatientStudyView>> GetCurrentVisitPatientStudyList(SubjectVisitStudyQuery inQuery)
{
var patientQuery = _studySubjectVisitRepository.Where(t => t.SubjectVisitId == inQuery.SujectVisitId && t.SubjectVisit.SubmitState != SubmitStateEnum.Submitted)
//.WhereIf(inQuery.SubmitState != null, u => u.SubjectVisit.SubmitState == inQuery.SubmitState)
.ProjectTo<VisitPatientStudyView>(_mapper.ConfigurationProvider);
var sortField = string.IsNullOrWhiteSpace(inQuery.SortField) ? nameof(VisitPatientStudyView.StudyTime) : inQuery.SortField;
var orderQuery = inQuery.Asc ? patientQuery.OrderBy(sortField) : patientQuery.OrderBy(sortField + " desc");
var list = await orderQuery.ToListAsync();
return list;
}
/// <summary>
/// 访视管理-> 获取可选访视列表 (从访视列表 进入修改绑定)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<List<VisitPatientStudyView>> GetPatientOtherStudyList(PatientStudyOtherQuery inQuery)
{
var query = from scpStudy in _studyRepository.Where(t => inQuery.PatientIdList.Contains(t.PatientId) && !t.SCPStudySubjectVisitList.Any(t => (t.SubjectVisitId == inQuery.SujectVisitId || t.SubjectVisit.SubmitState == SubmitStateEnum.Submitted) && t.TrialId == inQuery.TrialId))
.WhereIf(inQuery.EarliestStudyTime != null, t => t.StudyTime >= inQuery.EarliestStudyTime)
.WhereIf(inQuery.LatestStudyTime != null, t => t.StudyTime <= inQuery.LatestStudyTime)
.WhereIf(!string.IsNullOrEmpty(inQuery.PatientIdStr), t => t.PatientIdStr.Contains(inQuery.PatientIdStr))
//不属于该访视的检查 或者未绑定的检查
join scpStudySubjectVisit in _studySubjectVisitRepository.Where(c => c.TrialId == inQuery.TrialId) on scpStudy.Id equals scpStudySubjectVisit.SCPStudyId
into dd
from scpStudySV in dd.DefaultIfEmpty()
select new VisitPatientStudyView()
{
PatientIdStr = scpStudy.PatientIdStr,
PatientBirthDate = scpStudy.PatientBirthDate,
PatientAge = scpStudy.PatientAge,
PatientName = scpStudy.PatientName,
PatientSex = scpStudy.PatientSex,
Description = scpStudy.Description,
CalledAE = scpStudy.CalledAE,
CallingAE = scpStudy.CallingAE,
InstanceCount = scpStudy.InstanceCount,
Modalities = scpStudy.Modalities,
PatientId = scpStudy.PatientId,
SCPStudyId = scpStudy.Id,
SeriesCount = scpStudy.SeriesCount,
StudyTime = scpStudy.StudyTime,
SubmitState = scpStudySV.SubjectVisit.SubmitState,
SubjectVisitId = scpStudySV.SubjectVisitId,
VisitName = scpStudySV.SubjectVisit.VisitName,
};
#region 废弃
//var notCurrentVisitQuey = _studySubjectVisitRepository.Where(t => t.SubjectVisitId != inQuery.SujectVisitId && t.SCPStudy.Patient.Id == inQuery.PatientId)
// .Select(t => new VisitPatientStudyView()
// {
// Description = t.SCPStudy.Description,
// CalledAE = t.SCPStudy.CalledAE,
// InstanceCount = t.SCPStudy.InstanceCount,
// Modalities = t.SCPStudy.Modalities,
// PatientId = t.SCPStudy.PatientId,
// SCPStudyId = t.SCPStudy.PatientId,
// SeriesCount = t.SCPStudy.SeriesCount,
// StudyTime = t.SCPStudy.StudyTime,
// SubjectVisitId = t.SubjectVisitId,
// VisitName = t.SubjectVisit.VisitName,
// });
//var notBindQuery= _studyRepository.Where(t => t.PatientId == inQuery.PatientId && t.pa)
//var patientQuery = query
// .ProjectTo<VisitPatientStudyView>(_mapper.ConfigurationProvider);
#endregion
var sortField = string.IsNullOrWhiteSpace(inQuery.SortField) ? nameof(VisitPatientStudyView.StudyTime) : inQuery.SortField;
var orderQuery = inQuery.Asc ? query.OrderBy(sortField) : query.OrderBy(sortField + " desc");
var list = await orderQuery.ToListAsync();
return list;
}
#endregion
#region 检查管理
/// <summary>
///检查管理-> 检查列表 (同步影像数据之前的)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<PatientStudyBeforeConfirmView>>> GetPatientStudyBeforeConfirmList(TrialPatientStudyQuery inQuery)
{
#region 只查询已绑定的
//var query = _studySubjectVisitRepository.Where(t => t.SubjectVisit.TrialId == inQuery.TrialId)
// .WhereIf(inQuery.PatientId != null, t => t.SCPStudy.PatientId == inQuery.PatientId)
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectCode), u => u.SubjectVisit.Subject.Code.Contains(inQuery.SubjectCode))
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), u => u.SCPStudy.Patient.PatientIdStr.Contains(inQuery.PatientIdStr))
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientSex), t => t.SCPStudy.Patient.PatientSex.Contains(inQuery.PatientSex))
// .WhereIf(inQuery.SubjectAge != null, t => t.SubjectVisit.Subject.Age == inQuery.SubjectAge)
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectCode), u => u.SubjectVisit.Subject.Code.Contains(inQuery.SubjectCode))
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectSex), u => u.SubjectVisit.Subject.Sex.Contains(inQuery.SubjectSex))
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectShortName), t => t.SubjectVisit.Subject.ShortName.Contains(inQuery.SubjectShortName))
// .WhereIf(inQuery.BeginStudyTime != null, t => t.SCPStudy.StudyTime >= inQuery.BeginStudyTime)
// .WhereIf(inQuery.EndStudyTime != null, t => t.SCPStudy.StudyTime <= inQuery.EndStudyTime)
// .Select(t => new PatientStudyBeforeConfirmView()
// {
// SubjectId = t.SubjectVisit.SubjectId,
// SubjectAge = t.SubjectVisit.Subject.Age,
// SubjectSex = t.SubjectVisit.Subject.Sex,
// SubjectShortName = t.SubjectVisit.Subject.ShortName,
// PatientId = t.SCPStudy.PatientId,
// PatientAge = t.SCPStudy.PatientAge,
// PatientBirthDate = t.SCPStudy.PatientBirthDate,
// PatientIdStr = t.SCPStudy.PatientIdStr,
// PatientSex = t.SCPStudy.PatientSex,
// //PatientList = t.SubjectVisit.Subject.SubjectPatientList.Select(t => new PatientBasicInfo()
// //{
// // PatientId = t.PatientId,
// // PatientAge = t.Patient.PatientAge,
// // PatientBirthDate = t.Patient.PatientBirthDate,
// // PatientIdStr = t.Patient.PatientIdStr,
// // PatientSex = t.Patient.PatientSex,
// //}).ToList(),
// SubjectCode = t.SubjectVisit.Subject.Code,
// SubmitState = t.SubjectVisit.SubmitState,
// SubmitTime = t.SubjectVisit.SubmitTime,
// VisitName = t.SubjectVisit.VisitName,
// SubjectVisitId = t.SubjectVisitId,
// VisitEarliestStudyTime = t.SubjectVisit.SCPStudySubjectVisitList.Min(t => t.SCPStudy.StudyTime),
// VisitLatestStudyTime = t.SubjectVisit.SCPStudySubjectVisitList.Max(t => t.SCPStudy.StudyTime),
// StudyId = t.SCPStudyId,
// StudyTime = t.SCPStudy.StudyTime,
// CallingAE = t.SCPStudy.CallingAE,
// CalledAE = t.SCPStudy.CalledAE
// });
#endregion
var query = from scpStudy in _studyRepository.Where(t => !t.SCPStudySubjectVisitList.Any(t => t.SubjectVisit.SubmitState == SubmitStateEnum.Submitted && t.TrialId == inQuery.TrialId))
.WhereIf(inQuery.IsBindedVisit == false, t => !t.SCPStudySubjectVisitList.Any(t => t.TrialId == inQuery.TrialId))
.WhereIf(inQuery.IsBindedVisit == true, t => t.SCPStudySubjectVisitList.Any(t => t.TrialId == inQuery.TrialId))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.VisitName), t => t.SCPStudySubjectVisitList.Any(t => t.TrialId == inQuery.TrialId && t.SubjectVisit.VisitName.Contains(inQuery.VisitName)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientSex), t => t.Patient.PatientSex.Contains(inQuery.PatientSex))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), u => u.Patient.PatientIdStr.Contains(inQuery.PatientIdStr))
.WhereIf(inQuery.BeginStudyTime != null, t => t.StudyTime >= inQuery.BeginStudyTime)
.WhereIf(inQuery.EndStudyTime != null, t => t.StudyTime <= inQuery.EndStudyTime)
join subjectPatient in _subjectPatientRepository.Where(t => t.Subject.TrialId == inQuery.TrialId)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectCode), u => u.Subject.Code.Contains(inQuery.SubjectCode))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectSex), u => u.Subject.Sex.Contains(inQuery.SubjectSex))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectShortName), t => t.Subject.ShortName.Contains(inQuery.SubjectShortName))
on scpStudy.PatientId equals subjectPatient.PatientId
join scpStudySubjectVisit in _studySubjectVisitRepository.Where(t => t.TrialId == inQuery.TrialId)
on scpStudy.Id equals scpStudySubjectVisit.SCPStudyId into dd
from scpStudySV in dd.DefaultIfEmpty()
select new PatientStudyBeforeConfirmView()
{
SubjectId = subjectPatient.Subject.Id,
SubjectAge = subjectPatient.Subject.Age,
SubjectSex = subjectPatient.Subject.Sex,
SubjectShortName = subjectPatient.Subject.ShortName,
SubjectCode = subjectPatient.Subject.Code,
PatientId = scpStudy.PatientId,
PatientName = scpStudy.PatientName,
PatientAge = scpStudy.PatientAge,
PatientBirthDate = scpStudy.PatientBirthDate,
PatientIdStr = scpStudy.PatientIdStr,
PatientSex = scpStudy.PatientSex,
//PatientList = t.SubjectVisit.Subject.SubjectPatientList.Select(t => new PatientBasicInfo()
//{
// PatientId = t.PatientId,
// PatientAge = t.Patient.PatientAge,
// PatientBirthDate = t.Patient.PatientBirthDate,
// PatientIdStr = t.Patient.PatientIdStr,
// PatientSex = t.Patient.PatientSex,
//}).ToList(),
SubmitState = scpStudySV.SubjectVisit.SubmitState,
SubmitTime = scpStudySV.SubjectVisit.SubmitTime,
VisitName = scpStudySV.SubjectVisit.VisitName,
VisitNum = scpStudySV.SubjectVisit.VisitNum,
SubjectVisitId = scpStudySV.SubjectVisit.Id,
VisitEarliestStudyTime = scpStudySV.SubjectVisit.SCPStudySubjectVisitList.Min(t => t.SCPStudy.StudyTime),
VisitLatestStudyTime = scpStudySV.SubjectVisit.SCPStudySubjectVisitList.Max(t => t.SCPStudy.StudyTime),
StudyId = scpStudy.Id,
StudyTime = scpStudy.StudyTime,
CallingAE = scpStudy.CallingAE,
CalledAE = scpStudy.CalledAE,
Description = scpStudy.Description,
InstanceCount = scpStudy.InstanceCount,
Modalities = scpStudy.Modalities,
ModalityForEdit = scpStudy.ModalityForEdit,
SeriesCount = scpStudy.SeriesCount
};
var defalutSortArray = new string[] { nameof(PatientStudyBeforeConfirmView.SubjectCode), nameof(PatientStudyBeforeConfirmView.VisitNum), nameof(PatientStudyBeforeConfirmView.StudyTime) };
var pageList = await query.ToPagedListAsync(inQuery, defalutSortArray);
return ResponseOutput.Ok(pageList);
}
/// <summary>
///检查管理-> 检查列表 (同步影像数据之后的 带患者信息 患者信息是数组)
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<PatientStudyView>>> GetTrialPatientStudyList(TrialPatientStudyQuery inQuery, [FromServices] IRepository _repository)
{
var query = _repository.Where<DicomStudy>(t => t.SubjectVisit.TrialId == inQuery.TrialId)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectCode), u => u.SubjectVisit.Subject.Code.Contains(inQuery.SubjectCode))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), u => u.PatientIdStr.Contains(inQuery.PatientIdStr))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientSex), t => t.PatientSex.Contains(inQuery.PatientSex))
.WhereIf(inQuery.SubjectAge != null, t => t.SubjectVisit.Subject.Age == inQuery.SubjectAge)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectCode), u => u.SubjectVisit.Subject.Code.Contains(inQuery.SubjectCode))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectSex), u => u.SubjectVisit.Subject.Sex.Contains(inQuery.SubjectSex))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectShortName), t => t.SubjectVisit.Subject.ShortName.Contains(inQuery.SubjectShortName))
.WhereIf(inQuery.BeginStudyTime != null, t => t.StudyTime >= inQuery.BeginStudyTime)
.WhereIf(inQuery.EndStudyTime != null, t => t.StudyTime <= inQuery.EndStudyTime)
.Select(t => new PatientStudyView()
{
SubjectId = t.SubjectVisit.SubjectId,
SubjectAge = t.Subject.Age,
SubjectSex = t.Subject.Sex,
SubjectShortName = t.Subject.ShortName,
//PatientId = Guid.Empty,
PatientAge = t.PatientAge,
PatientName = t.PatientName,
PatientBirthDate = t.PatientBirthDate,
PatientIdStr = t.PatientIdStr,
PatientSex = t.PatientSex,
//PatientList = t.Subject.SubjectPatientList.Select(t => new PatientBasicInfo()
//{
// PatientId = t.PatientId,
// PatientAge = t.Patient.PatientAge,
// PatientBirthDate = t.Patient.PatientBirthDate,
// PatientIdStr = t.Patient.PatientIdStr,
// PatientSex = t.Patient.PatientSex,
//}).ToList(),
Modalities = t.Modalities,
ModalityForEdit = t.ModalityForEdit,
SubjectCode = t.SubjectVisit.Subject.Code,
SubmitState = t.SubjectVisit.SubmitState,
SubmitTime = t.SubjectVisit.SubmitTime,
VisitName = t.SubjectVisit.VisitName,
VisitNum = t.SubjectVisit.VisitNum,
SubjectVisitId = t.SubjectVisitId,
VisitEarliestStudyTime = t.SubjectVisit.StudyList.Min(t => t.StudyTime),
VisitLatestStudyTime = t.SubjectVisit.StudyList.Max(t => t.StudyTime),
StudyId = t.Id,
StudyTime = t.StudyTime,
Description = t.Description,
SeriesCount = t.SeriesCount,
InstanceCount = t.InstanceCount,
});
var defalutSortArray = new string[] { nameof(PatientStudyView.SubjectCode), nameof(PatientStudyView.VisitNum), nameof(PatientStudyView.StudyTime) };
var pageList = await query.ToPagedListAsync(inQuery, defalutSortArray);
return ResponseOutput.Ok(pageList);
}
/// <summary>
/// 获取该项目 患者已绑定subject ,新来了的检查 可能需要新建访视 但是新增的检查未绑定访视的检查列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<UnbindStudyView>>> GetTrialUnbindSubjectVisitStudyList(TrialPatientStudyQuery inQuery)
{
//属于该项目的已绑定患者的检查,同时没有绑定任何访视
var query = from scpStudy in _studyRepository.Where(t => !t.SCPStudySubjectVisitList.Any(t => t.TrialId == inQuery.TrialId))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientSex), t => t.Patient.PatientSex.Contains(inQuery.PatientSex))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), u => u.Patient.PatientIdStr.Contains(inQuery.PatientIdStr))
.WhereIf(inQuery.BeginStudyTime != null, t => t.StudyTime >= inQuery.BeginStudyTime)
.WhereIf(inQuery.EndStudyTime != null, t => t.StudyTime <= inQuery.EndStudyTime)
join subjectPatient in _subjectPatientRepository.Where(t => t.Subject.TrialId == inQuery.TrialId)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectCode), u => u.Subject.Code.Contains(inQuery.SubjectCode))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectSex), u => u.Subject.Sex.Contains(inQuery.SubjectSex))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectShortName), t => t.Subject.ShortName.Contains(inQuery.SubjectShortName))
on scpStudy.PatientId equals subjectPatient.PatientId
join scpStudySubjectVisit in _studySubjectVisitRepository.AsQueryable() on scpStudy.Id equals scpStudySubjectVisit.SCPStudyId
into dd
from scpStudySV in dd.DefaultIfEmpty()
select new UnbindStudyView()
{
PatientIdStr = scpStudy.PatientIdStr,
PatientBirthDate = scpStudy.PatientBirthDate,
PatientAge = scpStudy.PatientAge,
PatientName = scpStudy.PatientName,
PatientSex = scpStudy.PatientSex,
Description = scpStudy.Description,
CalledAE = scpStudy.CalledAE,
InstanceCount = scpStudy.InstanceCount,
Modalities = scpStudy.Modalities,
PatientId = scpStudy.PatientId,
SCPStudyId = scpStudy.Id,
SeriesCount = scpStudy.SeriesCount,
StudyTime = scpStudy.StudyTime,
SubjectVisitId = scpStudySV.SubjectVisitId,
VisitName = scpStudySV.SubjectVisit.VisitName,
SubjectId = subjectPatient.SubjectId,
SubjectCode = subjectPatient.Subject.Code,
TrialId = subjectPatient.Subject.TrialId,
SubjectAge = subjectPatient.Subject.Age,
SubjectSex = subjectPatient.Subject.Sex,
SubjectShortName = subjectPatient.Subject.ShortName,
SubjectBirthDate = subjectPatient.Subject.BirthDate
};
#region 废弃
//var query = from subject in _subjectRepository.Where(t => t.TrialId == inQuery.TrialId)
// .WhereIf(inQuery.SubjectAge != null, t => t.Age == inQuery.SubjectAge)
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectCode), u => u.Code.Contains(inQuery.SubjectCode))
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectSex), u => u.Sex.Contains(inQuery.SubjectSex))
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectShortName), t => t.ShortName.Contains(inQuery.SubjectShortName))
// join subjectPatient in _subjectPatientRepository.AsQueryable() on subject.Id equals subjectPatient.PatientId
// //没有绑定任何访视
// join scpStudy in _studyRepository.AsQueryable()
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientSex), t => t.Patient.PatientSex.Contains(inQuery.PatientSex))
// .WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), u => u.Patient.PatientIdStr.Contains(inQuery.PatientIdStr))
// .WhereIf(inQuery.BeginStudyTime != null, t => t.StudyTime >= inQuery.BeginStudyTime)
// .WhereIf(inQuery.EndStudyTime != null, t => t.StudyTime <= inQuery.EndStudyTime)
// on subjectPatient.PatientId equals scpStudy.PatientId
// select new SubjectPatientStudyView()
// {
// SubjectId = subject.Id,
// SubjectAge = subject.Age,
// SubjectSex = subject.Sex,
// SubjectShortName = subject.ShortName,
// PatientList = subject.SubjectPatientList.Select(t => new PatientBasicInfo()
// {
// PatientId = t.PatientId,
// PatientAge = t.Patient.PatientAge,
// PatientBirthDate = t.Patient.PatientBirthDate,
// PatientIdStr = t.Patient.PatientIdStr,
// PatientSex = t.Patient.PatientSex,
// }).ToList(),
// SubjectCode = subject.Code,
// SeriesCount = scpStudy.SeriesCount,
// CalledAE = scpStudy.CalledAE,
// InstanceCount = scpStudy.InstanceCount,
// Description = scpStudy.Description,
// Modalities = scpStudy.Modalities,
// PatientId = scpStudy.PatientId,
// SCPStudyId = scpStudy.Id,
// StudyTime = scpStudy.StudyTime
// };
#endregion
var pageList = await query.ToPagedListAsync(inQuery, nameof(UnbindStudyView.StudyTime));
return ResponseOutput.Ok(pageList);
}
/// <summary>
/// 删除某个项目 未提交的访视检查绑定, 清理数据,方便测试自动绑定
/// </summary>
/// <param name="trialId"></param>
/// <returns></returns>
[HttpDelete]
public async Task<IResponseOutput> DeleteUnSubmittedStudyBind(Guid trialId, Guid? subjectId,
[FromServices] IRepository<VisitTask> _visitTaskRepository,
[FromServices] IRepository<DicomStudy> _dicomStudyRepository,
[FromServices] IRepository<DicomSeries> _dicomSeriesRepository,
[FromServices] IRepository<DicomInstance> _dicomInstanceRepository)
{
if (subjectId != null)
{
await _studySubjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.TrialId == trialId && t.SubjectId == subjectId);
await _subjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
await _visitTaskRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
await _dicomStudyRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
await _dicomSeriesRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
await _dicomInstanceRepository.BatchDeleteNoTrackingAsync(t => t.SubjectId == subjectId);
}
else
{
await _studySubjectVisitRepository.BatchDeleteNoTrackingAsync(t => t.TrialId == trialId && t.SubjectVisit.SubmitState != SubmitStateEnum.Submitted);
}
return ResponseOutput.Ok();
}
/// <summary>
/// 阅片管理-> 任务列表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<PatientVisitTaskDTO>>> GetPatientVisitTaskList([FromServices] IRepository<VisitTask> _visitTaskRepository, PatientVisitTaskQuery inQuery)
{
var visitTaskQueryable = _visitTaskRepository.Where(t => t.TrialId == inQuery.TrialId && t.IsAnalysisCreate == false)
.WhereIf(inQuery.ReadingCategory != null, t => t.ReadingCategory == inQuery.ReadingCategory)
.WhereIf(inQuery.ReadingCategory == null, t => t.ReadingCategory != ReadingCategory.Judge)
.WhereIf(inQuery.ReadingTaskState != null, t => t.ReadingTaskState == inQuery.ReadingTaskState)
.WhereIf(inQuery.TaskState != null, t => t.TaskState == inQuery.TaskState)
.WhereIf(inQuery.SubjectId != null, t => t.SubjectId == inQuery.SubjectId)
.WhereIf(inQuery.DoctorUserId != null, t => t.DoctorUserId == inQuery.DoctorUserId)
.WhereIf(inQuery.TrialReadingCriterionId != null, t => t.TrialReadingCriterionId == inQuery.TrialReadingCriterionId)
.WhereIf(!string.IsNullOrEmpty(inQuery.TaskName), t => t.TaskName.Contains(inQuery.TaskName) || t.TaskBlindName.Contains(inQuery.TaskName))
.WhereIf(inQuery.BeginSignTime != null, t => t.SignTime >= inQuery.BeginSignTime)
.WhereIf(inQuery.EndSignTime != null, t => t.SignTime <= inQuery.EndSignTime)
.WhereIf(inQuery.BeginTaskCreateTime != null, t => t.CreateTime >= inQuery.BeginTaskCreateTime)
.WhereIf(inQuery.EndTaskCreateTime != null, t => t.CreateTime <= inQuery.EndTaskCreateTime)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientIdStr), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientIdStr.Contains(inQuery.PatientIdStr)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientName), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientName.Contains(inQuery.PatientName)))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.PatientSex), t => t.Subject.SubjectPatientList.Any(t => t.Patient.PatientSex.Contains(inQuery.PatientSex)))
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectShortName), t => t.Subject.ShortName.Contains(inQuery.SubjectShortName))
.WhereIf(!string.IsNullOrEmpty(inQuery.SubjectCode), t => (t.Subject.Code.Contains(inQuery.SubjectCode) && t.IsAnalysisCreate == false) || (t.BlindSubjectCode.Contains(inQuery.SubjectCode) && t.IsAnalysisCreate))
.ProjectTo<PatientVisitTaskDTO>(_mapper.ConfigurationProvider);
var defalutSortArray = new string[] { nameof(PatientVisitTaskDTO.SubjectId), nameof(PatientVisitTaskDTO.VisitTaskNum) };
var pageList = await visitTaskQueryable.ToPagedListAsync(inQuery, defalutSortArray);
return ResponseOutput.Ok(pageList);
}
#endregion
#region 影像下载
/// <summary>
/// 获取下载的访视检查信息
/// </summary>
/// <param name="trialId"></param>
/// <param name="subjectVisitId"></param>
/// <returns></returns>
public async Task<IResponseOutput> GetDownloadSubjectVisitStudyInfo(Guid trialId, Guid subjectVisitId)
{
var query = from sv in _subjectVisitRepository.Where(t => t.Id == subjectVisitId)
select new
{
TrialId = sv.TrialId,
SubjectId = sv.SubjectId,
SubjectCode = sv.Subject.Code,
VisitName = sv.VisitName,
StudyList = sv.StudyList
.Select(u => new
{
u.PatientIdStr,
u.StudyTime,
u.StudyCode,
SeriesList = u.SeriesList.Select(z => new
{
z.Modality,
InstanceList = z.DicomInstanceList.Select(k => new
{
k.Path,
k.FileSize
})
})
}).ToList(),
};
var result = query.FirstOrDefault();
var preDownloadInfo = new SubejctVisitDownload()
{
Id = NewId.NextSequentialGuid(),
IP = _userInfo.IP,
SubjectVisitId = subjectVisitId,
DownloadStartTime = DateTime.Now,
ImageCount = result.StudyList.Sum(s => s.SeriesList.Sum(s => s.InstanceList.Count())),
ImageSize = result.StudyList.Sum(t => t.SeriesList.Sum(s => s.InstanceList.Sum(i => i.FileSize))) ?? 0
};
await _subejctVisitDownloadRepository.AddAsync(preDownloadInfo, true);
return ResponseOutput.Ok(result, preDownloadInfo.Id);
}
/// <summary>
/// 影像下载成功回调
/// </summary>
/// <param name="trialImageDownloadId"></param>
/// <returns></returns>
[HttpGet]
public async Task<IResponseOutput> DownloadImageSuccess(Guid trialImageDownloadId)
{
await _subejctVisitDownloadRepository.UpdatePartialFromQueryAsync(t => t.Id == trialImageDownloadId, u => new SubejctVisitDownload()
{ DownloadEndTime = DateTime.Now, IsSuccess = true }, true);
return ResponseOutput.Ok();
}
/// <summary>
/// 访视影像下载记录表
/// </summary>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<VisitImageDownloadView>>> GetTrialSubjectVisitDownloadList(VisitImageDownloadQuery inQuery)
{
var query = _subejctVisitDownloadRepository.Where(t => t.SubjectVisit.TrialId == inQuery.TrialId)
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.IP), t => t.IP.Contains(inQuery.IP))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.SubjectCode), t => t.SubjectVisit.Subject.Code.Contains(inQuery.SubjectCode))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.VisitName), t => t.SubjectVisit.VisitName.Contains(inQuery.VisitName))
.WhereIf(!string.IsNullOrWhiteSpace(inQuery.Name), t => t.CreateUser.UserName.Contains(inQuery.Name) || t.CreateUser.FullName.Contains(inQuery.Name))
.WhereIf(inQuery.UserTypeEnum != null, t => t.CreateUser.UserTypeRole.UserTypeEnum == inQuery.UserTypeEnum)
.WhereIf(inQuery.BeginDownloadTime != null, t => t.CreateTime >= inQuery.BeginDownloadTime)
.WhereIf(inQuery.EndDownloadTime != null, t => t.CreateTime <= inQuery.EndDownloadTime)
.ProjectTo<VisitImageDownloadView>(_mapper.ConfigurationProvider);
var pageList = await query.ToPagedListAsync(inQuery, nameof(VisitImageDownloadQuery.SubjectCode));
return ResponseOutput.Ok(pageList);
}
#endregion
/// <summary>
/// scp 影像推送记录表
/// </summary>
/// <param name="inQuery"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<PageOutput<SCPImageUploadView>>> GetSCPImageUploadList(SCPImageUploadQuery inQuery)
{
var query = _SCPImageUploadRepository.Where()
.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))
.WhereIf(inQuery.StartTime != null, t => t.StartTime >= inQuery.StartTime)
.WhereIf(inQuery.EndTime != null, t => t.EndTime <= inQuery.EndTime)
.ProjectTo<SCPImageUploadView>(_mapper.ConfigurationProvider);
var pageList = await query.ToPagedListAsync(inQuery, nameof(SCPImageUploadView.CallingAE));
return ResponseOutput.Ok(pageList);
}
#region 作为SCU C-find c-move 操作
#region 基础方法
public static DicomCFindRequest CreateStudyRequest(SCUQuery inQuery, string modality/*, List<string> modalityList*/)
{
var request = new DicomCFindRequest(DicomQueryRetrieveLevel.Study);
// always add the encoding
request.Dataset.AddOrUpdate(new DicomTag(0x8, 0x5), "ISO_IR 100");
// add the dicom tags with empty values that should be included in the result of the QR Server
////病例号
//request.Dataset.AddOrUpdate(DicomTag.PatientID, "");
//request.Dataset.AddOrUpdate(DicomTag.PatientName, "");
//request.Dataset.AddOrUpdate(DicomTag.PatientSex, "");
//request.Dataset.AddOrUpdate(DicomTag.PatientBirthDate, "");
////检查号 设备类型
//request.Dataset.AddOrUpdate(DicomTag.StudyID, "");
//request.Dataset.AddOrUpdate(DicomTag.ModalitiesInStudy, "");
//request.Dataset.AddOrUpdate(DicomTag.StudyDate, "");
//request.Dataset.AddOrUpdate(DicomTag.StudyTime, "");
//request.Dataset.AddOrUpdate(DicomTag.BodyPartExamined, "");
//request.Dataset.AddOrUpdate(DicomTag.StudyDescription, "");
//request.Dataset.AddOrUpdate(DicomTag.StudyInstanceUID, "");
// add the dicom tags that contain the filter criterias
//request.Dataset.AddOrUpdate(DicomTag.PatientID, "Test*");
//var modalityQuery = string.Join($"\\", (inQuery.ModalitiesInStudyList == null || inQuery.ModalitiesInStudyList?.Count == 0) ? modalityList : inQuery.ModalitiesInStudyList);
//病例号
request.Dataset.AddOrUpdate(DicomTag.PatientID, inQuery.PatientID.IsNullOrEmpty() ? "" : inQuery.PatientID);
request.Dataset.AddOrUpdate(DicomTag.PatientName, inQuery.PatientName.IsNullOrEmpty() ? "" : inQuery.PatientName);
request.Dataset.AddOrUpdate(DicomTag.PatientSex, inQuery.PatientSex.IsNullOrEmpty() ? "" : inQuery.PatientSex);
request.Dataset.AddOrUpdate(DicomTag.PatientBirthDate, inQuery.PatientBirthDate.IsNullOrEmpty() ? "" : inQuery.PatientBirthDate);
//检查号 设备类型
request.Dataset.AddOrUpdate(DicomTag.StudyID, inQuery.StudyID.IsNullOrEmpty() ? "" : inQuery.StudyID);
request.Dataset.AddOrUpdate(DicomTag.AccessionNumber, inQuery.StudyID.IsNullOrEmpty() ? "" : inQuery.AccessionNumber);
request.Dataset.AddOrUpdate(DicomTag.Modality, "");
request.Dataset.AddOrUpdate(DicomTag.ModalitiesInStudy, modality);
request.Dataset.AddOrUpdate(DicomTag.StudyDate, inQuery.StudyDate.IsNullOrEmpty() ? "" : inQuery.StudyDate);
request.Dataset.AddOrUpdate(DicomTag.StudyTime, inQuery.StudyTime.IsNullOrEmpty() ? "" : inQuery.StudyTime);
request.Dataset.AddOrUpdate(DicomTag.StudyDescription, inQuery.StudyDescription.IsNullOrEmpty() ? "" : inQuery.StudyDescription);
request.Dataset.AddOrUpdate(DicomTag.StudyInstanceUID, inQuery.StudyInstanceUID.IsNullOrEmpty() ? "" : inQuery.StudyInstanceUID);
//测试
//request.Dataset.AddOrUpdate(DicomTag.SeriesInstanceUID, "");
//request.Dataset.AddOrUpdate(DicomTag.SeriesDescription, "");
//request.Dataset.AddOrUpdate(DicomTag.BodyPartExamined, inQuery.BodyPartExamined.IsNullOrEmpty() ? "" : inQuery.BodyPartExamined);
return request;
}
public static void DebugStudyResponse(DicomCFindResponse response, ILogger _logger)
{
if (response.Status == DicomStatus.Pending)
{
// print the results
_logger.LogDebug($"Patient {response.Dataset.GetSingleValueOrDefault(DicomTag.PatientName, string.Empty)}, {(response.Dataset.TryGetString(DicomTag.ModalitiesInStudy, out var dummy) ? dummy : string.Empty)}-Study from {response.Dataset.GetSingleValueOrDefault(DicomTag.StudyDate, new DateTime())} with UID {response.Dataset.GetSingleValueOrDefault(DicomTag.StudyInstanceUID, string.Empty)} ");
}
if (response.Status == DicomStatus.Success)
{
Console.WriteLine(response.Status.ToString());
}
}
#endregion
private bool CEchoTest(DicomAE find, string clientAE)
{
var client = DicomClientFactory.Create(find.IP, find.Port, false, clientAE, find.CalledAE);
client.NegotiateAsyncOps();
client.ServiceOptions.RequestTimeout = TimeSpan.FromSeconds(3);
var request = new DicomCEchoRequest
{
OnResponseReceived = (req, response) =>
{
if (response.Status == DicomStatus.Success)
{
find.IsTestOK = true;
}
else
{
find.IsTestOK = false;
}
}
};
return find.IsTestOK;
}
/// <summary>
/// 获取 检查列表
/// </summary>
/// <param name="inQuery"></param>
/// <param name="_dicomAEReposiotry"></param>
/// <param name="_logger"></param>
/// <returns></returns>
[HttpPost]
public async Task<IResponseOutput<List<SCUStudyView>>> GetCFindStudyList(SCUQuery inQuery,
[FromServices] IRepository<DicomAE> _dicomAEReposiotry,
[FromServices] ILogger<PatientService> _logger)
{
var result = new List<SCUStudyView>();
var find = await _dicomAEReposiotry.FirstOrDefaultAsync(t => t.Id == inQuery.PacsDicomAEId);
var hirClient = await _dicomAEReposiotry.FirstOrDefaultAsync(t => t.PacsTypeEnum == PacsType.HIRClient);
if (hirClient == null)
{
throw new BusinessValidationFailedException(_localizer["Patient_NoPacsClientAE"]);
}
if (find != null)
{
//测试失败
if (!CEchoTest(find, hirClient.CalledAE))
{
throw new BusinessValidationFailedException(_localizer["Patient_PacsAENotOnline"]);
}
var @lock = _distributedLockProvider.CreateLock($"CFind");
var client = DicomClientFactory.Create(find.IP, find.Port, false, hirClient.CalledAE, find.CalledAE);
client.NegotiateAsyncOps();
DicomCFindRequest.ResponseDelegate responseDelegate = (req, response) =>
{
if (response.HasDataset)
{
using (@lock.Acquire())
{
var maxStudyCount = find.MaxStudyCount > 0 ? find.MaxStudyCount : 50;
//查询该项目下的患者,那么不限制总数,否则需要限制总数
if (inQuery.TrialId == null && result.Count >= maxStudyCount)
{
response.Status = DicomStatus.Cancel;
return;
}
else
{
var studyTime = response.Dataset.GetDateTime(DicomTag.StudyDate, DicomTag.StudyTime);
DateOnly datePart = DateOnly.FromDateTime(studyTime);
TimeOnly timePart = TimeOnly.FromDateTime(studyTime);
var canParce = DateTime.TryParseExact(response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.PatientBirthDate, ""), "yyyyMMdd", null, System.Globalization.DateTimeStyles.None, out DateTime birthDate);
// 格式化为你需要的日期格式例如yyyy-MM-dd
string formattedBirthDate = canParce ? birthDate.ToString("yyyy-MM-dd") : string.Empty;
result.Add(new SCUStudyView()
{
PatientID = response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.PatientID, ""),
PatientName = response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.PatientName, ""),
PatientSex = response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.PatientSex, ""),
PatientBirthDate = formattedBirthDate,
StudyID = response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.StudyID, ""),
AccessionNumber = response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.AccessionNumber, ""),
ModalitiesInStudy = response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.ModalitiesInStudy, ""),
Modality = response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.Modality, ""),
StudyDate = datePart.ToString("yyyy-MM-dd"),
StudyTime = timePart.ToString("HH:mm:ss"),
BodyPartExamined = response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.BodyPartExamined, ""),
StudyDescription = response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.StudyDescription, ""),
StudyInstanceUID = response.Dataset?.GetSingleValueOrDefault<string>(DicomTag.StudyInstanceUID, "")
});
}
}
}
};
//看当前前端有没有传递modality有的话以前端为准没有的话以配置为准 构造同样数量的请求
var requestModalityList = (inQuery.ModalitiesInStudyList != null && inQuery.ModalitiesInStudyList.Count > 0) ? inQuery.ModalitiesInStudyList : find.ModalityList;
if (inQuery.TrialId == null)
{
//判断前段有没有传递时间
if (find.PacsSearchMaxDays != 0)
{
//0 天 + 前端不传递就是不限制
inQuery.StudyDate = inQuery.StudyDate.IsNullOrEmpty() ? $"{DateTime.Now.AddDays(-(find.PacsSearchMaxDays - 1)).ToString("yyyyMMdd")}-{DateTime.Now.ToString("yyyyMMdd")}" : inQuery.StudyDate;
}
if (find.IsSupportMutiModality)
{
//支持多模态的Pacs
var modality = string.Join($"\\", requestModalityList);
var request = CreateStudyRequest(inQuery, modality);
request.OnResponseReceived += responseDelegate;
await client.AddRequestAsync(request);
}
else
{
foreach (var modality in requestModalityList)
{
var cloneInQuery = inQuery.Clone();
var request = CreateStudyRequest(cloneInQuery, modality);
request.OnResponseReceived += responseDelegate;
await client.AddRequestAsync(request);
}
}
await client.SendAsync();
}
else
{
//找到该项目下的患者,以及每个患者最新的检查之后的检查
var list = await _subjectRepository.Where(t => t.TrialId == inQuery.TrialId).SelectMany(t => t.SubjectPatientList)
.WhereIf(inQuery.PatientID.IsNotNullOrEmpty(), t => t.Patient.PatientIdStr == inQuery.PatientID)
.Select(t => new
{
t.Patient.PatientIdStr,
MaxStudyTime = t.Patient.SCPStudyList.Max(t => t.StudyTime),
//仅用提交时间
VisitMaxSubmitTime = t.Subject.SubjectVisitList.Max(t => t.SubmitTime)
}).ToListAsync();
foreach (var patient in list)
{
var cloneInQuery = inQuery.Clone();
cloneInQuery.PatientID = patient.PatientIdStr;
if (find.PacsSearchMaxDays != 0)
{
// pacs 支持的时间
// 访视提交的时间
if (patient.VisitMaxSubmitTime != null && patient.VisitMaxSubmitTime > DateTime.Now.AddDays(-(find.PacsSearchMaxDays - 1)))
{
cloneInQuery.StudyDate = patient.VisitMaxSubmitTime?.ToString("yyyyMMdd") + "-";
cloneInQuery.StudyTime = patient.VisitMaxSubmitTime?.ToString("HHmmss") + "-";
}
else
{
//pacs 限制的时间
cloneInQuery.StudyDate = $"{DateTime.Now.AddDays(-(find.PacsSearchMaxDays - 1)).ToString("yyyyMMdd")}-{DateTime.Now.ToString("yyyyMMdd")}";
}
}
else
{
if (patient.VisitMaxSubmitTime != null)
{
cloneInQuery.StudyDate = patient.VisitMaxSubmitTime?.ToString("yyyyMMdd") + "-";
cloneInQuery.StudyTime = patient.VisitMaxSubmitTime?.ToString("HHmmss") + "-";
}
}
#region 区分时间查询
////选择了患者,那么不按照患者最新检查时间之后查询(因为可能存在,先拉去了后面的检查,导致前面的检查查询不到)
//if (inQuery.PatientID.IsNotNullOrEmpty())
//{
// // pacs 支持的时间
// // 访视提交的时间
// if (patient.VisitMaxSubmitTime != null)
// {
// cloneInQuery.StudyDate = patient.VisitMaxSubmitTime?.ToString("yyyyMMdd") + "-";
// cloneInQuery.StudyTime = patient.VisitMaxSubmitTime?.ToString("HHmmss") + "-";
// }
//}
//else
//{
// //没有选择患者,那么按照每个患者的最大检查时间之后的查询
// if (patient.MaxStudyTime != null)
// {
// cloneInQuery.StudyDate = patient.MaxStudyTime?.ToString("yyyyMMdd") + "-";
// cloneInQuery.StudyTime = patient.MaxStudyTime?.ToString("HHmmss") + "-";
// }
//}
#endregion
var request = CreateStudyRequest(cloneInQuery, find.IsSupportMutiModality ? string.Join($"\\", requestModalityList) : "");
request.OnResponseReceived += responseDelegate;
await client.AddRequestAsync(request);
}
await client.SendAsync();
}
var resultInstanceUidList = result.Select(t => t.StudyInstanceUID).ToList();
var existStudyIdList = _studyRepository.Where(t => resultInstanceUidList.Contains(t.StudyInstanceUid))
.Select(t => t.StudyInstanceUid).ToList();
foreach (var item in result)
{
item.IsStudyExist = existStudyIdList.Any(t => t == item.StudyInstanceUID);
}
if (inQuery.TrialId != null)
{
result = result.Where(t => t.IsStudyExist == false).ToList();
}
}
return ResponseOutput.Ok(result, find);
}
#region 获取项目维度拉取影像数据下拉框
public async Task<List<NewTrialSelectDTO>> GetUserJoinedTrialPatientList()
{
var trialQuery = _trialRepository
.WhereIf(_userInfo.UserTypeEnumInt != (int)UserTypeEnum.SuperAdmin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.Admin && _userInfo.UserTypeEnumInt != (int)UserTypeEnum.OA
, t => t.TrialUserList.Any(t => t.UserId == _userInfo.Id && t.IsDeleted == false) && t.IsDeleted == false)
.Select(t => new NewTrialSelectDTO()
{
TrialId = t.Id,
TrialCode = t.TrialCode,
ResearchProgramNo = t.ResearchProgramNo,
ExperimentName = t.ExperimentName,
CreateTime = t.CreateTime,
TrialStatusStr = t.TrialStatusStr,
PatientList = t.SubjectList.Where(t => t.Status == SubjectStatus.OnVisit).SelectMany(t => t.SubjectPatientList).Select(u => new TrialPatientDTO()
{
PatientAge = u.Patient.PatientAge,
PatientIdStr = u.Patient.PatientIdStr,
PatientName = u.Patient.PatientName,
PatientSex = u.Patient.PatientSex
}).ToList()
});
var list = await trialQuery.OrderBy(t => t.CreateTime).ToListAsync();
return list;
}
#endregion
/// <summary>
/// 批量验证Cmove 检查在系统存在与否
/// </summary>
/// <param name="inCommand"></param>
/// <returns></returns>
public async Task<Dictionary<string, object>> CMoveVerify(SCUCmoveCommand inCommand)
{
var existStudyIdList = _studyRepository.Where(t => inCommand.StudyInstanceUIDList.Contains(t.StudyInstanceUid))
.Select(t => new { t.StudyInstanceUid, t.StudyId, PatientId = t.PatientIdStr, t.AccessionNumber, t.PatientName }).ToList();
var dic = new Dictionary<string, object>();
foreach (var item in inCommand.StudyInstanceUIDList)
{
var find = existStudyIdList.FirstOrDefault(t => t.StudyInstanceUid == item);
dic.Add(item, find == null ? string.Empty : find);
}
return dic;
}
/// <summary>
/// 拉取影像
/// </summary>
/// <param name="inCommand"></param>
/// <param name="_dicomAEReposiotry"></param>
/// <param name="_scpInstanceRepository"></param>
/// <param name="_basicSystemConfigConfig"></param>
/// <returns></returns>
public async Task<IResponseOutput> CmoveStudyList(SCUCmoveCommand inCommand,
[FromServices] IRepository<DicomAE> _dicomAEReposiotry,
[FromServices] IRepository<SCPInstance> _scpInstanceRepository,
[FromServices] IOptionsMonitor<ServiceVerifyConfigOption> _basicSystemConfigConfig)
{
var result = new List<SCUStudyView>();
var find = await _dicomAEReposiotry.FirstOrDefaultAsync(t => t.Id == inCommand.PacsDicomAEId);
var hirServer = await _dicomAEReposiotry.FirstOrDefaultAsync(t => t.PacsTypeEnum == PacsType.HIRServer);
var hirClient = await _dicomAEReposiotry.FirstOrDefaultAsync(t => t.PacsTypeEnum == PacsType.HIRClient);
if (hirServer == null)
{
//"未找到服务端AE配置请核查后再拉取"
return ResponseOutput.NotOk(_localizer["Patient_NoPacsAE"]);
}
if (hirClient == null)
{
return ResponseOutput.NotOk(_localizer["Patient_NoPacsClientAE"]);
}
if (find != null)
{
DicomCMoveRequest.ResponseDelegate responseDelegate = (req, response) =>
{
if (response.Status.State == DicomState.Failure || response.Status.State == DicomState.Cancel)
{
_logger.LogError($" Cmove Pacs 返回状态: {response.Status.State} {response.SOPClassUID.ToJsonNotIgnoreNull()}");
_fusionCache.Set<string?>(CacheKeys.CmoveStudyId(req.Dataset.GetString(DicomTag.StudyInstanceUID)), null, TimeSpan.FromSeconds(1));
}
// 判断是否传输完成或中断,执行缓存清理
if (response.Status.State == DicomState.Success && response.Remaining == 0)
{
_fusionCache.Set<string?>(CacheKeys.CmoveStudyId(req.Dataset.GetString(DicomTag.StudyInstanceUID)), null, TimeSpan.FromSeconds(1));
}
};
var latestInstanceList = await _scpInstanceRepository.Where(t => inCommand.StudyInstanceUIDList.Contains(t.StudyInstanceUid))
.GroupBy(t => t.StudyInstanceUid).Select(g => g.OrderByDescending(t => t.CreateTime).FirstOrDefault()).ToListAsync();
var task = Task.Run(async () =>
{
var client = DicomClientFactory.Create(find.IP, find.Port, false, hirClient.CalledAE, find.CalledAE);
client.NegotiateAsyncOps();
var cmoveRequestList = new List<DicomCMoveRequest>();
foreach (var item in inCommand.StudyInstanceUIDList)
{
var cmoveConfig = _basicSystemConfigConfig.CurrentValue;
var exsitStudyId = await _fusionCache.GetOrDefaultAsync<string>(CacheKeys.CmoveStudyId(item), null);
var latestInstance = latestInstanceList.Where(t => t.StudyInstanceUid == item).FirstOrDefault();
//缓存不存在当前检查或者instance表最新的记录时间与当前时间之差超过1分钟认为完成归档可以重复拉取
if (exsitStudyId == null && (latestInstance == null || latestInstance?.CreateTime.AddMinutes(cmoveConfig.CmoveInstanceIntervalMinutes) < DateTime.Now))
{
await _fusionCache.SetAsync(CacheKeys.CmoveStudyId(item), item, TimeSpan.FromMinutes(cmoveConfig.CmoveIntervalMinutes));
var cmoveRequest = new DicomCMoveRequest(hirServer.CalledAE, item);
cmoveRequest.OnResponseReceived += responseDelegate;
cmoveRequestList.Add(cmoveRequest);
_logger.LogInformation($"执行C-Move StudyInstanceUID{item}");
}
else
{
_logger.LogInformation($"忽略C-Move StudyInstanceUID{item}");
}
}
await client.AddRequestsAsync(cmoveRequestList);
await client.SendAsync();
});
//await task;
}
return ResponseOutput.Ok();
}
#endregion
}
}