From 633abdf0f406ca50c90803850e80af7beeeb6200 Mon Sep 17 00:00:00 2001 From: hang <872297557@qq.com> Date: Tue, 27 Aug 2024 14:47:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=97=B6=E9=97=B4=E5=9B=BD?= =?UTF-8?q?=E9=99=85=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Controllers/ExtraController.cs | 10 +- .../NewtonsoftJson/CustomJsonResult .cs | 125 +++++++++++++++ .../NewtonsoftJson/JSONTimeZoneConverter.cs | 45 ++++-- .../NewtonsoftJson/NewtonsoftJsonSetup.cs | 27 ++-- .../ImageAndDoc/DTO/UnionStudyViewDodel.cs | 19 ++- .../ImageAndDoc/DownloadAndUploadService.cs | 143 +++++++++++++++++- .../Image/NoneDicomStudyFile.cs | 19 ++- IRaCIS.Core.Domain/Trial/Trial.cs | 2 +- 8 files changed, 359 insertions(+), 31 deletions(-) create mode 100644 IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/CustomJsonResult .cs diff --git a/IRaCIS.Core.API/Controllers/ExtraController.cs b/IRaCIS.Core.API/Controllers/ExtraController.cs index 3c9875df9..7cbff77f7 100644 --- a/IRaCIS.Core.API/Controllers/ExtraController.cs +++ b/IRaCIS.Core.API/Controllers/ExtraController.cs @@ -362,8 +362,11 @@ namespace IRaCIS.Api.Controllers var client = new Client(new AlibabaCloud.OpenApiClient.Models.Config() { - AccessKeyId = ossOptions.accessKeyId, - AccessKeySecret = ossOptions.accessKeySecret, + //AccessKeyId = ossOptions.accessKeyId, + //AccessKeySecret = ossOptions.accessKeySecret, + AccessKeyId = "LTAI5tJV76pYX5yPg1N9QVE8", + AccessKeySecret = "roRNLa9YG1of4pYruJGCNKBXEWTAWa", + Endpoint = "sts.cn-hangzhou.aliyuncs.com" }); @@ -371,7 +374,8 @@ namespace IRaCIS.Api.Controllers // 将设置为自定义的会话名称,例如oss-role-session。 assumeRoleRequest.RoleSessionName = $"session-name-{NewId.NextGuid()}"; // 将替换为拥有上传文件到指定OSS Bucket权限的RAM角色的ARN。 - assumeRoleRequest.RoleArn = ossOptions.roleArn; + //assumeRoleRequest.RoleArn = ossOptions.roleArn; + assumeRoleRequest.RoleArn = "acs:ram::1899121822495495:role/webdirect"; assumeRoleRequest.DurationSeconds = 3600; var runtime = new AlibabaCloud.TeaUtil.Models.RuntimeOptions(); var response = client.AssumeRoleWithOptions(assumeRoleRequest, runtime); diff --git a/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/CustomJsonResult .cs b/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/CustomJsonResult .cs new file mode 100644 index 000000000..557112b9d --- /dev/null +++ b/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/CustomJsonResult .cs @@ -0,0 +1,125 @@ +using IRaCIS.Core.Domain.Share; +using Microsoft.AspNetCore.Builder; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.Extensions.DependencyInjection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using System; +using System.Globalization; +using System.Threading.Tasks; + +namespace IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson +{ + public class CustomJsonResult : JsonResult + { + public CustomJsonResult(object value) : base(value) { } + + public override void ExecuteResult(ActionContext context) + { + var converter = context.HttpContext.RequestServices.GetService(); + + var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US; + string dateFormat; + + if (!isEn_US) + { + // Chinese date format + dateFormat = "yyyy-MM-dd HH:mm:ss"; + } + else + { + // Default or English date format + dateFormat = "MM/dd/yyyy HH:mm:ss"; + } + + var serializerSettings = new JsonSerializerSettings + { + DateFormatString = dateFormat, + ReferenceLoopHandling = ReferenceLoopHandling.Ignore, + ContractResolver = new NullToEmptyStringResolver(), + DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind, + + }; + serializerSettings.Converters.Add(converter); + var json = JsonConvert.SerializeObject(Value, serializerSettings); + context.HttpContext.Response.ContentType = "application/json"; + context.HttpContext.Response.WriteAsync(json); + } + } + + + public class MyDateTimeConverter : JsonConverter + { + public override DateTime ReadJson(JsonReader reader, Type objectType, DateTime existingValue, bool hasExistingValue, JsonSerializer serializer) + { + return reader.ReadAsDateTime().Value; + } + + public override void WriteJson(JsonWriter writer, DateTime value, JsonSerializer serializer) + { + var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US; + + string dateFormat; + if (!isEn_US) + { + // Chinese date format + dateFormat = "yyyy-MM-dd HH:mm:ss"; + } + else + { + // Default or English date format + dateFormat = "MM/dd/yyyy HH:mm:ss"; + } + + writer.WriteValue(value.ToString(dateFormat)); + + } + } + + public class MyNullableDateTimeConverter : JsonConverter + { + public override DateTime? ReadJson(JsonReader reader, Type objectType, DateTime? existingValue, bool hasExistingValue, JsonSerializer serializer) + { + var val = reader.ReadAsDateTime(); + return val; + } + + public override void WriteJson(JsonWriter writer, DateTime? value, JsonSerializer serializer) + { + var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US; + + string dateFormat; + if (!isEn_US) + { + // Chinese date format + dateFormat = "yyyy-MM-dd HH:mm:ss"; + } + else + { + // Default or English date format + dateFormat = "MM/dd/yyyy HH:mm:ss"; + } + + if (value.HasValue) + { + writer.WriteValue(value.Value.ToString(dateFormat)); + + } + else + { + writer.WriteValue(default(DateTime?)); + } + + } + } + + + + + + + + +} diff --git a/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/JSONTimeZoneConverter.cs b/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/JSONTimeZoneConverter.cs index 0968daf29..ce758306c 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/JSONTimeZoneConverter.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/JSONTimeZoneConverter.cs @@ -11,19 +11,39 @@ namespace IRaCIS.Core.API /// /// 序列化,反序列化的时候,处理时间 时区转换 /// - public class JSONTimeZoneConverter : DateTimeConverterBase + public class JSONTimeZoneConverter(IHttpContextAccessor _httpContextAccessor) : DateTimeConverterBase { - private readonly IHttpContextAccessor _httpContextAccessor; - private readonly TimeZoneInfo _clientTimeZone; - public JSONTimeZoneConverter(IHttpContextAccessor httpContextAccessor) + private TimeZoneInfo _clientTimeZone; + + private string _dateFormat; + + + + public override bool CanConvert(Type objectType) { - _httpContextAccessor = httpContextAccessor; + #region 设置语言格式化方式,放在构造函数里面做不到动态切换 + + + var isEn_US = CultureInfo.CurrentCulture.Name == StaticData.CultureInfo.en_US; + + if (!isEn_US) + { + // Chinese date format + _dateFormat = "yyyy-MM-dd HH:mm:ss"; + } + else + { + // Default or English date format + _dateFormat = "MM/dd/yyyy HH:mm:ss"; + } + + #endregion + + #region 获取当前请求的客户端时区 - //默认是UTC //var timeZoneId = "Etc/UTC"; var timeZoneId = "Asia/Shanghai"; - var timeZoneIdHeader = _httpContextAccessor?.HttpContext?.Request?.Headers["TimeZoneId"]; if (timeZoneIdHeader is not null && !string.IsNullOrEmpty(timeZoneIdHeader.Value)) @@ -33,12 +53,12 @@ namespace IRaCIS.Core.API _clientTimeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); - } + #endregion + - public override bool CanConvert(Type objectType) - { // 仅支持 DateTime 类型的转换 return objectType == typeof(DateTime)|| objectType == typeof(DateTime?); + } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) @@ -91,7 +111,10 @@ namespace IRaCIS.Core.API { //第一个参数默认使用系统本地时区 也就是应用服务器的时区 DateTime clientZoneTime = TimeZoneInfo.ConvertTime(nullableDateTime.Value, _clientTimeZone); - writer.WriteValue(clientZoneTime); + + //writer.WriteValue(clientZoneTime); + + writer.WriteValue(clientZoneTime.ToString(_dateFormat)); } else { diff --git a/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/NewtonsoftJsonSetup.cs b/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/NewtonsoftJsonSetup.cs index 69032ff19..49a8cbdb1 100644 --- a/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/NewtonsoftJsonSetup.cs +++ b/IRaCIS.Core.API/_ServiceExtensions/NewtonsoftJson/NewtonsoftJsonSetup.cs @@ -1,10 +1,14 @@  using IRaCIS.Core.API._ServiceExtensions.NewtonsoftJson; using IRaCIS.Core.Application.Helper; +using IRaCIS.Core.Domain.Share; +using Microsoft.AspNetCore.Mvc.Infrastructure; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.DependencyInjection; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using System; +using System.Globalization; namespace IRaCIS.Core.API { @@ -12,37 +16,40 @@ namespace IRaCIS.Core.API { public static void AddNewtonsoftJsonSetup(this IMvcBuilder builder, IServiceCollection services) { + services.AddHttpContextAccessor(); services.AddScoped(); services.AddScoped(); services.AddScoped(); + + builder.AddNewtonsoftJson(options => { - //options.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects; // 忽略循环引用 options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; - //options.SerializerSettings.TypeNameHandling = TypeNameHandling.All; //处理返回给前端 可空类型 给出默认值 比如in? 为null 设置 默认值0 - options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver(); //new DefaultContractResolver();// new NullToEmptyStringResolver(); - // 设置时间格式 - options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; + options.SerializerSettings.ContractResolver = new NullToEmptyStringResolver(); + + // 设置时间格式 isEn_US? "MM/dd/yyyy HH:mm:ss" : + //options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss"; options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; + //二者只能取其一 + //options.SerializerSettings.Converters.Add(new MyDateTimeConverter()); + //options.SerializerSettings.Converters.Add(new MyNullableDateTimeConverter()); + + //必须放在后面 options.SerializerSettings.Converters.Add(services.BuildServiceProvider().GetService()); - - //IsoDateTimeConverter - //options.SerializerSettings.NullValueHandling = NullValueHandling.Ignore; - }) .AddControllersAsServices()//动态webApi属性注入需要 .ConfigureApiBehaviorOptions(o => - { + { o.SuppressModelStateInvalidFilter = true; //自己写验证 ////这里是自定义验证结果和返回状态码 因为这里是在[ApiController]控制器层校验,动态webApi的不会校验 所以需要单独写一个Filter diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/UnionStudyViewDodel.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/UnionStudyViewDodel.cs index be29c21d3..2a2f45b16 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/UnionStudyViewDodel.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/DTO/UnionStudyViewDodel.cs @@ -46,7 +46,7 @@ namespace IRaCIS.Core.Application.Contracts public bool IsDicom { get; set; } - + } public class UnionStudyMonitorModel : UnionStudyBaseModel @@ -363,4 +363,21 @@ namespace IRaCIS.Core.Application.Contracts public decimal FileFize { get; set; } } + + public class CRCUploadedStudyQuqry + { + [NotDefault] + public Guid SubjectVisitId { get; set; } + + public List DicomStudyIdList { get; set; } + + public List NoneDicomStudyIdList { get; set; } + } + + public class IRReadingDownloadQuery + { + [NotDefault] + public Guid VisitTaskId { get; set; } + + } } diff --git a/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs b/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs index 58a9b9415..6ddf4bbf1 100644 --- a/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs +++ b/IRaCIS.Core.Application/Service/ImageAndDoc/DownloadAndUploadService.cs @@ -45,7 +45,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc IRepository _readingQuestionCriterionTrialRepository, IDistributedLockProvider _distributedLockProvider) : BaseService, IDownloadAndUploadService { - + /// /// 受试者随机阅片,任务进行随机编号 @@ -490,7 +490,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc { - var extralConfig = _trialRepository.Where(t => t.Id == trialId).Select(t => t.TrialExtraConfigJsonStr).FirstOrDefault() ?? string.Empty; + var extralConfig = _trialRepository.Where(t => t.Id == trialId).Select(t => t.TrialExtraConfigJsonStr).FirstOrDefault() ?? string.Empty; var config = JsonConvert.DeserializeObject(extralConfig) ?? new TrialExtraConfig(); @@ -608,7 +608,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc } else if (inQuery.SubejctId != null) { - var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubejctId).SelectMany(t=>t.SubjectVisitList) + var query = from sv in _subjectRepository.Where(t => t.Id == inQuery.SubejctId).SelectMany(t => t.SubjectVisitList) select new @@ -656,7 +656,7 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc } else { - return ResponseOutput.NotOk("不允许 subjectId subjectId 都不传递"); + return ResponseOutput.NotOk("不允许 subjectId SubejectVisitId 都不传递"); } @@ -894,5 +894,140 @@ namespace IRaCIS.Core.Application.Service.ImageAndDoc } + + /// + /// IQC 获取CRC 上传到某一个访视的的检查信息 (原始影像信息 包含dicom 非dicom) + /// + /// + /// + [HttpPost] + public async Task GetCRCUploadedStudyInfo(CRCUploadedStudyQuqry inQuery) + { + var isQueryDicom = inQuery.DicomStudyIdList.Count > 0; + var isQueryNoneDicom = inQuery.NoneDicomStudyIdList.Count > 0; + + var query = from sv in _subjectVisitRepository.Where(t => t.Id == inQuery.SubjectVisitId) + + + select new + { + SubjectCode = sv.Subject.Code, + VisitName = sv.VisitName, + + StudyList = sv.StudyList.Where(t => isQueryDicom ? inQuery.DicomStudyIdList.Contains(t.Id):false) + + .Select(u => new + { + u.PatientId, + u.StudyTime, + u.StudyCode, + + SeriesList = u.SeriesList.Select(z => new + { + z.Modality, + + InstanceList = z.DicomInstanceList.Select(k => new + { + k.Path, + k.FileSize + }) + }) + + }).ToList(), + + NoneDicomStudyList = sv.NoneDicomStudyList.Where( t => isQueryNoneDicom?inQuery.NoneDicomStudyIdList.Contains(t.Id):false) + + .Select(nd => new + { + nd.Modality, + nd.StudyCode, + nd.ImageDate, + + FileList = nd.NoneDicomFileList.Select(file => new + { + file.FileName, + file.Path, + file.FileType + }) + }).ToList() + }; + + var result = query.ToList(); + + return ResponseOutput.Ok(result); + } + + + /// + /// IR 阅片页面获取下载检查的信息 会根据标准进行过滤检查,(后端要考虑到一致性分析 subjectCode的问题) + /// + /// + /// + [HttpPost] + public async Task GetIRReadingDownloadStudyInfo(IRReadingDownloadQuery inQuery) + { + var taskInfo = await _visitTaskRepository.Where(t => t.Id == inQuery.VisitTaskId) + .Select(t => new + { + t.BlindSubjectCode, + t.IsAnalysisCreate, + t.SourceSubjectVisitId, + t.TrialReadingCriterion.IsImageFilter, + t.TrialReadingCriterion.CriterionModalitys + }) + .FirstNotNullAsync(); + + if (taskInfo.SourceSubjectVisitId == null) + { + return ResponseOutput.NotOk("请开发核实传递的参数,该查询任务关联访视Id没有值"); + } + + var query = from sv in _subjectVisitRepository.Where(t => t.Id == taskInfo.SourceSubjectVisitId) + + + select new + { + SubjectCode = sv.Subject.Code, + VisitName = sv.VisitName, + StudyList = sv.StudyList.AsQueryable().WhereIf(taskInfo.IsImageFilter, t => ("|" + taskInfo.CriterionModalitys + "|").Contains("|" + t.ModalityForEdit + "|")) + .Select(u => new + { + u.PatientId, + u.StudyTime, + u.StudyCode, + + SeriesList = u.SeriesList.Select(z => new + { + z.Modality, + + InstancePathList = z.DicomInstanceList.Select(k => new + { + k.Path + }) + }) + + }), + + NoneDicomStudyList = sv.NoneDicomStudyList.AsQueryable().WhereIf(taskInfo.IsImageFilter, t => ("|" + taskInfo.CriterionModalitys + "|").Contains("|" + t.Modality + "|")) + .Select(nd => new + { + nd.Modality, + nd.StudyCode, + nd.ImageDate, + + FileList = nd.NoneDicomFileList.Select(file => new + { + file.FileName, + file.Path, + file.FileType + }) + }) + }; + + return ResponseOutput.Ok(); + } + } + + } diff --git a/IRaCIS.Core.Domain/Image/NoneDicomStudyFile.cs b/IRaCIS.Core.Domain/Image/NoneDicomStudyFile.cs index 199aad976..ecd0a58d1 100644 --- a/IRaCIS.Core.Domain/Image/NoneDicomStudyFile.cs +++ b/IRaCIS.Core.Domain/Image/NoneDicomStudyFile.cs @@ -18,6 +18,14 @@ namespace IRaCIS.Core.Domain.Models [ForeignKey("NoneDicomStudyId")] [JsonIgnore] public NoneDicomStudy NoneDicomStudy { get; set; } + + + [JsonIgnore] + public VisitTask VisitTask { get; set; } + + //[ForeignKey("OriginNoneDicomStudyId")] + //[JsonIgnore] + //public NoneDicomStudy OriginNoneDicomStudy { get; set; } #endregion @@ -31,7 +39,16 @@ namespace IRaCIS.Core.Domain.Models public string FileType { get; set; } - public decimal? FileSize { get; set; } + public long? FileSize { get; set; } + + + #region 跟任务绑定 同时区分检查 + + public Guid? VisitTaskId { get; set; } + + public Guid? OriginNoneDicomStudyId { get; set; } + #endregion + } diff --git a/IRaCIS.Core.Domain/Trial/Trial.cs b/IRaCIS.Core.Domain/Trial/Trial.cs index b47d8d4fb..6fbd4ea2e 100644 --- a/IRaCIS.Core.Domain/Trial/Trial.cs +++ b/IRaCIS.Core.Domain/Trial/Trial.cs @@ -79,7 +79,7 @@ namespace IRaCIS.Core.Domain.Models public List clinicalDataTrialSets { get; set; } = new List { }; [JsonIgnore] - public List ClinicalTrialProjectDetails { get; set; } + public List ClinicalTrialProjectDetails { get; set; } = new List { }; [JsonIgnore] public List TrialDicList { get; set; } = new List();