diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.csproj b/IRaCIS.Core.API/IRaCIS.Core.API.csproj index 8ddb0f03d..b85f69250 100644 --- a/IRaCIS.Core.API/IRaCIS.Core.API.csproj +++ b/IRaCIS.Core.API/IRaCIS.Core.API.csproj @@ -112,6 +112,18 @@ Always + + Always + + + Always + + + Always + + + Always + diff --git a/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/ReportTemplate_IRECIST_CN_V1.docx b/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/ReportTemplate_IRECIST_CN_V1.docx new file mode 100644 index 000000000..02037e28e Binary files /dev/null and b/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/ReportTemplate_IRECIST_CN_V1.docx differ diff --git a/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/ReportTemplate_PCWG3_CN_V1.docx b/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/ReportTemplate_PCWG3_CN_V1.docx new file mode 100644 index 000000000..c05aef561 Binary files /dev/null and b/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/ReportTemplate_PCWG3_CN_V1.docx differ diff --git a/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/ReportTemplate_RECIST1.1_CN_V1.docx b/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/ReportTemplate_RECIST1.1_CN_V1.docx new file mode 100644 index 000000000..44b3c18cf Binary files /dev/null and b/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/ReportTemplate_RECIST1.1_CN_V1.docx differ diff --git a/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/downLoad/file.txt b/IRaCIS.Core.API/wwwroot/ReadReoprtTemplate/downLoad/file.txt new file mode 100644 index 000000000..e69de29bb diff --git a/IRaCIS.Core.Application/Helper/OSSService.cs b/IRaCIS.Core.Application/Helper/OSSService.cs index c8c63a73a..9cc175465 100644 --- a/IRaCIS.Core.Application/Helper/OSSService.cs +++ b/IRaCIS.Core.Application/Helper/OSSService.cs @@ -38,6 +38,8 @@ public class AWSOptions public string ViewEndpoint { get; set; } public int DurationSeconds { get; set; } public string Region { get; set; } + + public string viewEndpoint { get; set; } } public class AliyunOSSOptions diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index c6111944e..a1622de6d 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -2521,6 +2521,88 @@ + + + 空转为横线 + + + + + + + 获取word图片 + + + + + + + + + 获取word图片 + + + + + + + + + 最大宽高 + + + + + + + + + + 获取任务问题答案 + + 问题答案 + 字典数据 + 单位字典 + 任务Id + 任务类型 + + + + + 获取报告No + + + + + + + 获取并复制文件流 + + + + + + + + 获取任务表格问题答案 + + 表格答案 + 字典 + 单位字典 + 任务Id + 病灶类型 + 问题标识 + 索引 + + + + + 获取病灶的图片 rowinfoList要带question的信息 + + + + + 标准和服务对应 @@ -2533,6 +2615,34 @@ + + + 下载阅片报告 + + + + + + + 删除文件 + + + + + + 下载阅片报告流 + + + + + + + + 获取并生成报告URL + + + + 自动计算 并修改值 @@ -2601,6 +2711,13 @@ + + + 下载阅片报告 + + + + 获取Sod的值 @@ -2981,6 +3098,13 @@ + + + 下载阅片报告 + + + + 获取Sod的值 @@ -3110,6 +3234,13 @@ + + + 下载阅片报告 + + + + 获取Sod的值 @@ -3631,6 +3762,13 @@ + + + 下载阅片报告 + + + + 获取阅片的计算数据 @@ -4159,6 +4297,13 @@ + + + 下载阅片报告 + + + + 获取阅片的计算数据 @@ -4337,6 +4482,13 @@ + + + 下载阅片报告 + + + + 删除病灶获取起始病灶序号 @@ -4443,6 +4595,13 @@ + + + 下载阅片报告 + + + + 获取Sod的值 @@ -4694,6 +4853,13 @@ + + + 下载阅片报告 + + + + 获取Sod的值 @@ -4998,6 +5164,13 @@ + + + 下载阅片报告 + + + + 获取阅片的计算数据 @@ -5096,6 +5269,13 @@ + + + 下载阅片报告 + + + + 获取ReadingCalculateDto @@ -5134,6 +5314,96 @@ + + + 获取图片 + + + + + + + + + 获取图片 + + + + + + + + + 下载文件 + + + + + + + + 获取并复制文件流 + + + + + + + 最大宽高 保持比例 + + + + + + + + + + 空转为横线 + + + + + + + 获取病灶的图片 rowinfoList要带question的信息 + + + + + + + + + 获取任务问题答案 + + 问题答案 + 字典数据 + 单位字典 + 任务Id + 任务类型 + + + + + 获取任务表格问题答案 + + 表格答案 + 字典 + 单位字典 + 任务Id + 病灶类型 + 问题标识 + 索引 + + + + + 获取阅片报告 + + + + 自动计算 并修改值 @@ -5182,6 +5452,27 @@ + + + 下载阅片报告 + + + + + + + 获取阅片报告流 + + + + + + + 获取并生成报告URl + + + + SubjectCriteriaEvaluationService @@ -6846,6 +7137,11 @@ 值 + + + 任务Id + + 阅片计算Dto @@ -7486,6 +7782,16 @@ 任务Id + + + 任务Id + + + + + 任务Id + + 问题类型 @@ -11896,6 +12202,20 @@ IR影像阅片 + + + 下载阅片报告 + + + + + + + 获取阅片报告 + + + + 获取阅片的计算数据 diff --git a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingCalculateViewModel.cs b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingCalculateViewModel.cs index 00e20b823..796d8453a 100644 --- a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingCalculateViewModel.cs +++ b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingCalculateViewModel.cs @@ -291,6 +291,29 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto public List SheetNames { get; set; } } + + + public class ExportReportQuestion + { + public string QuestionName { get; set; } + + public QuestionType QuestionType { get; set; } + } + + + public class DownLoadReadReportInDto + { + /// + /// 任务Id + /// + public Guid VisitTaskId { get; set; } + + public Guid DownLoadGuid { get; set; } + } + + + + /// /// 阅片计算Dto /// diff --git a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs index e165d3563..fcafbd6a3 100644 --- a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs +++ b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingImageTaskViewModel.cs @@ -446,6 +446,24 @@ namespace IRaCIS.Core.Application.Service.Reading.Dto } + public class CaGetVisitReadReportUrl + { + /// + /// 任务Id + /// + public Guid VisitTaskId { get; set; } + + } + + + public class GenerateReadingReportInDto + { + /// + /// 任务Id + /// + public Guid VisitTaskId { get; set; } + } + public class GetPreviousOtherPicturePathInDto { diff --git a/IRaCIS.Core.Application/Service/Reading/Interface/IReadingImageTaskService.cs b/IRaCIS.Core.Application/Service/Reading/Interface/IReadingImageTaskService.cs index 45c59a834..11b73f720 100644 --- a/IRaCIS.Core.Application/Service/Reading/Interface/IReadingImageTaskService.cs +++ b/IRaCIS.Core.Application/Service/Reading/Interface/IReadingImageTaskService.cs @@ -41,5 +41,7 @@ namespace IRaCIS.Core.Application.Contracts Task> GetReadingPastResultList(GetReadingPastResultListInDto inDto); + Task<(List, object)> GetRelatedVisitTask(GetRelatedVisitTaskInDto inDto); + } } \ No newline at end of file diff --git a/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs b/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs index 733d7bc52..6d714ca4d 100644 --- a/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs +++ b/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs @@ -68,6 +68,31 @@ namespace IRaCIS.Core.Application.Service + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReport(DownLoadReadReportInDto inDto) + { + return await _readingCalculateService.DownLoadReadReport(inDto); + } + + /// + /// 获取阅片报告 + /// + /// + /// + [HttpPost] + public async Task GetVisitReadReportUrl(GenerateReadingReportInDto inDto) + { + return await _readingCalculateService.GetVisitReadReportUrl(new CaGetVisitReadReportUrl() + { + VisitTaskId = inDto.VisitTaskId, + }); + } + + #region 计算 /// diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/General/GeneralCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/General/GeneralCalculateService.cs index 5333bcaed..f445bcb6a 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/General/GeneralCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/General/GeneralCalculateService.cs @@ -3,10 +3,15 @@ using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore.Common; +using IRaCIS.Core.Infrastructure; using MassTransit; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using MiniExcelLibs; +using MiniSoftware; +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; using System.Data; using System.IO; using System.Text; @@ -21,6 +26,7 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate IRepository _readingTableAnswerRowInfoRepository, IRepository _readingQuestionTrialRepository, IRepository _subjectVisitRepository, + IOptionsMonitor _options, IRepository _tumorAssessmentRepository, IRepository _readingTaskQuestionAnswerRepository, IRepository _inspectionFileRepository, @@ -482,5 +488,381 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate }); return taskInfoList; } + + + + /// + /// 空转为横线 + /// + /// + /// + public Dictionary StringEmptyTurnedLine(Dictionary myDictionary) + { + foreach (var item in myDictionary) + { + if (item.Value == null) + { + myDictionary[item.Key] = "-"; + } + else if (item.Value.GetType() == typeof(string)) + { + if (item.Value.ToString() == string.Empty || item.Value == null) + { + myDictionary[item.Key] = "-"; + }; + + } + else if (item.Value.GetType() == typeof(List>)) + { + var value = item.Value; + + foreach (var column in value as List>) + { + foreach (var item2 in column) + { + if (item2.Value.ToString() == string.Empty || item.Value == null) + { + column[item2.Key] = "-"; + }; + } + + } + + myDictionary[item.Key] = value; + + } + + } + return myDictionary; + + } + + /// + /// 获取word图片 + /// + /// + /// + /// + /// + public async Task GetWordPicture(string url, string savePath, int width) + { + var resultUrl = await this.FileDownSave(url, savePath); + + int picWidth = 0; + int picHeight = 0; + + + + using (var bitmap = Image.Load(resultUrl)) + { + // 获取图片的宽度和高度 + picWidth = bitmap.Width; + picHeight = bitmap.Height; + } + + var height = width * picHeight / picWidth; + + return new MiniWordPicture() + { + Path = resultUrl, + Height = height, + Width = width + }; + } + + /// + /// 获取word图片 + /// + /// + /// + /// + /// + public async Task GetWordPicture(string url, string savePath, int width, int height) + { + var resultUrl = await this.FileDownSave(url, System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/downLoad")); + + return new MiniWordPicture() + { + Path = resultUrl, + Height = height, + Width = width + }; + } + + /// + /// 最大宽高 + /// + /// + /// + /// + /// + /// + public async Task GetWordPictureMaxWL(string url, string savePath, int width, int height) + { + var resultUrl = await this.FileDownSave(url, savePath); + + + int picWidth = 0; + int picHeight = 0; + using (var bitmap = Image.Load(resultUrl)) + { + // 获取图片的宽度和高度 + picWidth = bitmap.Width; + picHeight = bitmap.Height; + } + + if (picWidth / picHeight > width / height) + { + height = width * picHeight / picWidth; + + } + else + { + width = height * picWidth / picHeight; + + } + + + return new MiniWordPicture() + { + Path = resultUrl, + Height = height, + Width = width + }; + } + + /// + /// 获取任务问题答案 + /// + /// 问题答案 + /// 字典数据 + /// 单位字典 + /// 任务Id + /// 任务类型 + /// + public string GetTaskanswer(List? answerList, List? dictionList, List? unitDictionary, Guid taskId, QuestionType questionType) + { + var answerData = answerList.FirstOrDefault(x => x.VisitTaskId == taskId && x.ReadingQuestionTrial.QuestionType == questionType); + if (answerData == null || answerData.Answer == string.Empty) + { + return string.Empty; + } + var answer = string.Empty; + if (answerData.ReadingQuestionTrial.QuestionGenre == TableQuestionType.Dictionary) + { + answer = dictionList.Where(x => x.Code == answerData.ReadingQuestionTrial.DictionaryCode).SelectMany(x => x.ChildList).Where(x => x.Code == answerData.Answer).Select(x => x.ValueCN).FirstIsNullReturnEmpty(); + } + else + { + answer = answerData.Answer; + } + if (answer != "NA" && answerData.ReadingQuestionTrial.Unit != null && answerData.ReadingQuestionTrial.Unit != ValueUnit.none) + { + answer += " " + unitDictionary.SelectMany(x => x.ChildList).Where(x => x.Code == ((int)answerData.ReadingQuestionTrial.Unit).ToString()).Select(x => x.ValueCN).FirstIsNullReturnEmpty(); + } + if (answer != "NA" && answerData.ReadingQuestionTrial.ValueType == ValueOfType.Percentage) + { + answer += " %"; + + } + + return answer; + } + + + /// + /// 获取报告No + /// + /// + /// + public async Task GetReportExportNo(VisitTask visitTaskInfo) + { + if (visitTaskInfo.ReportExportDate != null && visitTaskInfo.ReportExportNum != null) + { + return visitTaskInfo.ReportExportDate.Value.ToString("yyyyMMdd") + visitTaskInfo.ReportExportNum.ToString().PadLeft(4, '0'); + } + else + { + DateTime today = DateTime.Today; + + + var reportExportNum = await _visitTaskRepository.Where(x => x.TrialId == visitTaskInfo.TrialId && x.ReportExportDate != null && x.ReportExportDate.Value.Date == today).MaxAsync(x => x.ReportExportNum); + reportExportNum = reportExportNum == null ? 0 : reportExportNum; + await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.Id == visitTaskInfo.Id, x => new VisitTask() + { + + ReportExportDate = today, + ReportExportNum = reportExportNum + 1 + }); + + return today.ToString("yyyyMMdd") + (reportExportNum + 1).ToString().PadLeft(4, '0'); + + } + } + + + + /// + /// 获取并复制文件流 + /// + /// + /// + public Stream ReadAndReturnStream(string outputFilePath) + { + byte[] data; + + using (Stream stream = new FileStream(outputFilePath, FileMode.Open, FileAccess.Read)) + { + // 从流中读取数据保存到内存中 + using (MemoryStream memoryStream = new MemoryStream()) + { + stream.CopyTo(memoryStream); + data = memoryStream.ToArray(); + } + } + + // 返回内存中的数据作为新的流 + return new MemoryStream(data); + } + + /// + /// 下载并保存 + /// + /// 网络路径 + /// 保存本地的文件夹 + /// A + public async Task FileDownSave(string url, string savePath) + { + try + { + HttpClient httpClient = new HttpClient(); + if (!string.IsNullOrWhiteSpace(url)) + { + string[] strArry = url.Split('/'); + savePath = savePath + "/" + strArry[strArry.Length - 1]; + } + + var t = httpClient.GetByteArrayAsync(url); + t.Wait(); + Stream responseStream = new MemoryStream(t.Result); + Stream stream = new FileStream(savePath, FileMode.Create); + byte[] bArr = new byte[1024]; + int size = responseStream.Read(bArr, 0, bArr.Length); + while (size > 0) + { + stream.Write(bArr, 0, size); + size = responseStream.Read(bArr, 0, bArr.Length); + } + + stream.Close(); + responseStream.Close(); + + return savePath; + } + catch (Exception) + { + + throw new BusinessValidationFailedException(_localizer["ReadingCalculate_ImageNotExist"]); + } + + + } + + /// + /// 获取任务表格问题答案 + /// + /// 表格答案 + /// 字典 + /// 单位字典 + /// 任务Id + /// 病灶类型 + /// 问题标识 + /// 索引 + /// + public string GetTaskTableAnswer(List? tableAnswerList, List? dictionList, List? unitDictionary, Guid taskId, LesionType lesionType, QuestionMark questionMark, decimal rowIndex) + { + var answerData = tableAnswerList.FirstOrDefault(x => x.VisitTaskId == taskId && x.ReadingQuestionTrial.LesionType == lesionType && x.ReadingTableQuestionTrial.QuestionMark == questionMark && x.RowIndex == rowIndex); + + if (answerData == null || answerData.Answer == string.Empty) + { + return string.Empty; + } + var answer = string.Empty; + if (answerData.ReadingTableQuestionTrial.TableQuestionType == TableQuestionType.Dictionary) + { + answer = dictionList.Where(x => x.Code == answerData.ReadingTableQuestionTrial.DictionaryCode).SelectMany(x => x.ChildList).Where(x => x.Code == answerData.Answer).Select(x => x.ValueCN).FirstIsNullReturnEmpty(); + + } + else + { + answer = answerData.Answer; + + } + if (answer != "NA" && answerData.ReadingTableQuestionTrial.Unit != null && answerData.ReadingTableQuestionTrial.Unit != ValueUnit.none) + { + answer += " " + unitDictionary.SelectMany(x => x.ChildList).Where(x => x.Code == ((int)answerData.ReadingTableQuestionTrial.Unit).ToString()).Select(x => x.ValueCN).FirstIsNullReturnEmpty(); + } + + if (answer != "NA" && answerData.ReadingTableQuestionTrial.ValueType == ValueOfType.Percentage) + { + answer += " %"; + + } + + return answer; + } + + + /// + /// 获取病灶的图片 rowinfoList要带question的信息 + /// + /// + /// + /// + public async Task>> GetLesionPic(List rowinfoList, LesionType lesionType, Guid DownLoadGuid) + { + var lesionRowinfo = rowinfoList.Where(x => x.PicturePath != string.Empty && x.ReadingQuestionTrial.LesionType == lesionType).OrderBy(x => x.VisitTask.VisitTaskNum).OrderBy(x => x.RowIndex).ToList(); + List> lesionImage = new List>(); + + + var lesionCount = lesionRowinfo.Select(x => x.VisitTask.VisitTaskNum).Distinct().OrderBy(x => x).ToList(); + + int picNum = 0; + + foreach (var num in lesionCount) + { + var picRowinfo = lesionRowinfo.Where(x => x.VisitTask.VisitTaskNum == num).OrderBy(x => x.RowIndex).ToList(); + var picCount = picRowinfo.Count(); + for (int i = 0; i < Math.Ceiling((double)picCount / 2); i++) + { + lesionImage.Add(new Dictionary() + { + { "ImageOneMark",getPicNum(true)+ picRowinfo[2*i].VisitTask.TaskName+" "+picRowinfo[2*i].RowMark}, + { "ImageOneUrl" ,await GetWordPictureMaxWL(_options.CurrentValue.MinIO.viewEndpoint+picRowinfo[2*i].PicturePath ,System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{DownLoadGuid}"),290,390) }, + { "ImageTwoMark",getPicNum(picCount>2*i+1) + (picCount<=2*i+1?string.Empty:picRowinfo[2*i+1].VisitTask.TaskName+" "+picRowinfo[2*i+1].RowMark) }, + { "ImageTwoUrl", picCount<=2*i+1?string.Empty:await GetWordPictureMaxWL(_options.CurrentValue.MinIO.viewEndpoint+picRowinfo[2*i+1].PicturePath ,System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{DownLoadGuid}"),290, 390) }, + + }); + } + } + + string getPicNum(bool isHavePic) + { + if (isHavePic) + { + picNum += 1; + + return $"图{picNum} "; + + } + else + { + return string.Empty; + } + } + + return lesionImage; + + } } } diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/General/ReadingCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/General/ReadingCalculateService.cs index 688854f61..89789f83b 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/General/ReadingCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/General/ReadingCalculateService.cs @@ -1,4 +1,5 @@ -using IRaCIS.Core.Application.Service.Reading.Dto; +using IRaCIS.Core.Application.Helper; +using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infrastructure; @@ -7,12 +8,14 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using MiniExcelLibs; using System.Data; +using System.Runtime.InteropServices; namespace IRaCIS.Core.Application.Service.ReadingCalculate { [ApiExplorerSettings(GroupName = "Image")] public class ReadingCalculateService(IEnumerable _criterionServices, IRepository _visitTaskRepository, + IOSSService _oSSService, IRepository _readingQuestionCriterionTrialRepository, IStringLocalizer _localizer, IUserInfo _userInfo @@ -81,6 +84,131 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate } } + + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReport(DownLoadReadReportInDto inDto) + { + var service = await this.GetService(inDto.VisitTaskId); + if (service != null) + { + inDto.DownLoadGuid = Guid.NewGuid(); + Stream stream = await service.DownLoadReadReportStream(inDto); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + FileStreamResult actionResult = new FileStreamResult(stream, new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream")); + + actionResult.FileDownloadName = "ReadReoprtTemplate.docx"; + + + this.DeleteFile(inDto); + return actionResult; + } + else + { + FileStreamResult actionResult = new FileStreamResult(stream, new Microsoft.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream")); + actionResult.FileDownloadName = "ReadReoprtTemplate.pdf"; + this.DeleteFile(inDto); + return actionResult; + } + + } + else + { + throw new BusinessValidationFailedException("error"); + } + } + + /// + /// 删除文件 + /// + /// + + public void DeleteFile(DownLoadReadReportInDto inDto) + { + + + + try + { + File.Delete(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}.docx")); + + } + catch (Exception) + { + + } + + try + { + File.Delete(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}.pdf")); + + } + catch (Exception) + { + + } + + } + + /// + /// 下载阅片报告流 + /// + /// + /// + /// + public async Task DownLoadReadReportStream(DownLoadReadReportInDto inDto) + { + var service = await this.GetService(inDto.VisitTaskId); + if (service != null) + { + inDto.DownLoadGuid = Guid.NewGuid(); + var result = await service.DownLoadReadReportStream(inDto); + this.DeleteFile(inDto); + return result; + + } + else + { + throw new BusinessValidationFailedException(_localizer["ReadingCalculate_DownLoadReadReport"]); + } + } + + /// + /// 获取并生成报告URL + /// + /// + /// + public async Task GetVisitReadReportUrl(CaGetVisitReadReportUrl inDto) + { + var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.Subject).Include(x => x.SourceSubjectVisit).FirstNotNullAsync(); + if (taskinfo.ReportExportUrl != string.Empty) + { + return taskinfo.ReportExportUrl; + } + else + { + var stream = await DownLoadReadReportStream(new DownLoadReadReportInDto() + { + VisitTaskId = inDto.VisitTaskId, + }); + var url = await _oSSService.UploadToOSSAsync(stream, $"ReadingReport/{taskinfo.TrialId.ToString()}/{taskinfo.Id.ToString()}", $"{taskinfo.Subject.Code}_{taskinfo.SourceSubjectVisit.VisitName}.pdf", false); + + await _visitTaskRepository.BatchUpdateNoTrackingAsync(x => x.Id == inDto.VisitTaskId, x => new VisitTask() + { + ReportExportUrl = url + }); + return url; + + } + + } + + /// /// 自动计算 并修改值 /// diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/IRECIST1Point1CalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/IRECIST1Point1CalculateService.cs index 33890e963..68e484310 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/IRECIST1Point1CalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/IRECIST1Point1CalculateService.cs @@ -1,11 +1,19 @@ -using IRaCIS.Core.Application.Service.Reading.Dto; +using IRaCIS.Application.Contracts; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Helper; +using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.ViewModel; +using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore.Common; using IRaCIS.Core.Infrastructure; using MassTransit; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using MiniSoftware; +using System.Runtime.InteropServices; using System.Text; namespace IRaCIS.Core.Application.Service.ReadingCalculate @@ -24,9 +32,18 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate IRepository _tumorAssessmentRepository, IGeneralCalculateService _generalCalculateService, IRepository _readingTaskQuestionAnswerRepository, + IRepository _subjectRepository, + IRepository _userRepository, + IServiceProvider ServiceProvider, + IOptionsMonitor _hospital, + IRepository _dictionaryRepository, + IRepository _dicomStudyRepository, + IRepository _subjectPatientRepository, ILogger _logger, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ICriterionCalculateService { + + /// /// 获取阅片的计算数据 /// @@ -39,6 +56,277 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate }; } + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReportStream(DownLoadReadReportInDto inDto) + { + + var downFile = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}"); + Directory.CreateDirectory(downFile); + var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId && x.ReadingCategory == ReadingCategory.Visit) + .Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); + var visitInfo = await _subjectVisitRepository.Where(x => x.Id == taskinfo.SourceSubjectVisitId).Include(x => x.StudyList).FirstNotNullAsync(); + var subjectInfo = await _subjectRepository.Where(x => x.Id == taskinfo.SubjectId).Include(x => x.SubjectPatientList).FirstNotNullAsync(); + var doctor = await _userRepository.Where(x => x.Id == taskinfo.DoctorUserId).FirstOrDefaultAsync(); + + var trialQuestion = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).ToListAsync(); + var tableQuestion = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionTrial.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).ToListAsync(); + var dicotionCode = trialQuestion.Where(x => x.DictionaryCode != string.Empty).Select(x => x.DictionaryCode).Distinct().ToList(); + dicotionCode.AddRange(tableQuestion.Where(x => x.DictionaryCode != string.Empty).Select(x => x.DictionaryCode).Distinct()); + var dictionList = await _dictionaryRepository.Where(x => dicotionCode.Contains(x.Code)).Include(x => x.ChildList).ToListAsync(); + List taskIds = new List() { }; + var relatedVisitTask = await ServiceProvider.GetService().GetRelatedVisitTask(new GetRelatedVisitTaskInDto() + { + VisitTaskId = inDto.VisitTaskId + }); + + var relatedCount = relatedVisitTask.Item1.Count(); + + if (relatedCount <= 3) + { + taskIds = relatedVisitTask.Item1.Select(x => x.VisitTaskId).ToList(); + } + else + { + var count = relatedVisitTask.Item1.Count(); + taskIds.Add(relatedVisitTask.Item1[0].VisitTaskId); + taskIds.Add(relatedVisitTask.Item1[count - 2].VisitTaskId); + taskIds.Add(relatedVisitTask.Item1[count - 1].VisitTaskId); + + } + relatedVisitTask.Item1 = relatedVisitTask.Item1.Where(x => taskIds.Contains(x.VisitTaskId)).ToList(); + // 所有访视问题的答案 + var answerList = await _readingTaskQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.ReadingQuestionTrial).ToListAsync(); + + // 单位字典 + var unitDictionary = await _dictionaryRepository.Where(x => x.Code == "ValueUnit").Include(x => x.ChildList).ToListAsync(); + var imageProblem = _generalCalculateService.GetTaskanswer(answerList, dictionList, unitDictionary, inDto.VisitTaskId, QuestionType.ImageQualityAssessment); + var rowinfoList = await _readingTableAnswerRowInfoRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.VisitTask).Include(x => x.ReadingQuestionTrial).ToListAsync(); + var tableAnswerList = await _readingTableQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.ReadingQuestionTrial).Include(x => x.ReadingTableQuestionTrial).ToListAsync(); + + #region 获取各个病灶 + List> getLesionInfo(LesionType lesionType) + { + List targetFocusNum = rowinfoList.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionTrial.LesionType == lesionType).Select(x => x.RowIndex).OrderBy(x => x).ToList(); + + List> targetInfo = new List>(); + + foreach (var item in targetFocusNum) + { + var bodyPartDescription = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, inDto.VisitTaskId, lesionType, QuestionMark.BodyPartDescription, item); + + var rowMark = rowinfoList.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == item && x.ReadingQuestionTrial.LesionType == lesionType).Select(x => x.RowMark).FirstIsNullReturnEmpty(); + + var reportMark = rowinfoList.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == item && x.ReadingQuestionTrial.LesionType == lesionType).Select(x => x.ReportMark).FirstIsNullReturnEmpty(); + + if (reportMark != string.Empty) + { + rowMark = $"{rowMark}({reportMark})"; + + } + Dictionary target = new Dictionary() + { + { "RowMark",rowMark}, + { "Organ",_generalCalculateService.GetTaskTableAnswer(tableAnswerList,dictionList,unitDictionary,inDto.VisitTaskId,lesionType,QuestionMark.Organ,item)+":"+_generalCalculateService.GetTaskTableAnswer(tableAnswerList,dictionList,unitDictionary,inDto.VisitTaskId,lesionType,QuestionMark.Part,item)+ (bodyPartDescription==string.Empty?string.Empty:","+bodyPartDescription) }, + { "FirstVisit",getStateInfo(0,item, lesionType) }, + { "SecondVisit", relatedCount>=2?getStateInfo(1,item,lesionType):string.Empty }, + { "ThirdlyVisit", relatedCount>=3?getStateInfo(2,item,lesionType):string.Empty }, + }; + targetInfo.Add(target); + } + return targetInfo; + } + + string getStateInfo(int index, decimal item, LesionType lesionType) + { + // 非淋巴结取长径 淋巴结取长短径 + var state = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.State, item); + var majorAxis = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.MajorAxis, item); + + var isLymph = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.IsLymph, item); + var shortAxis = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.ShortAxis, item); + + var result = string.Empty; + + if (!state.IsNullOrEmpty()) + { + result = state; + + } + + if (!majorAxis.IsNullOrEmpty()) + { + result += result == string.Empty ? $"L:{majorAxis}" : $",L:{majorAxis}"; + } + + if (isLymph.EqEnum(YesOrNoOrNa.Yes) && !shortAxis.IsNullOrEmpty()) + { + result += result == string.Empty ? $"S:{shortAxis}" : $",S:{shortAxis}"; + } + + return result; + + } + + #endregion + + + #region 外层问题处理 + + // 获取外层问题 + List> getQuestionAnswerList(List exports) + { + List> questionAnswerList = new List>(); + foreach (var item in exports) + { + Dictionary questionAnswer = new Dictionary() + { + {"Name",item.QuestionName }, + {"FirstVisit", _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[0],item.QuestionType)}, + {"SecondVisit", relatedCount>=2? _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[1],item.QuestionType):string.Empty }, + {"ThirdlyVisit", relatedCount>=3? _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[2],item.QuestionType):string.Empty }, + }; + questionAnswerList.Add(questionAnswer); + } + return questionAnswerList; + } + + #endregion + + var studyInfo = (await _dicomStudyRepository.Where(x => x.SubjectVisitId == taskinfo.SourceSubjectVisitId).Select(x => new + { + + x.Modalities, + x.StudyTime, + x.BodyPartExamined, + x.Description + + }).OrderBy(x => x.StudyTime).ToListAsync()).Select(x => new Dictionary() { + + { "Modalities",x.Modalities}, + { "StudyTime",x.StudyTime?.ToString("yyyy-MM-dd")}, + { "Description",x.Description}, + { "ImageProblem",imageProblem}, + }).ToList(); + + + var subjectPatientList = await _subjectPatientRepository.Where(x => x.SubjectId == subjectInfo.Id).Include(x => x.Patient).ToListAsync(); + + + var resultList = new List() + { new ExportReportQuestion (){ QuestionName="靶病灶径线之和(SOD)",QuestionType=QuestionType.SOD}, + new ExportReportQuestion (){ QuestionName="非淋巴结靶病灶长径之和",QuestionType=QuestionType.SumOfDiameter}, + new ExportReportQuestion (){ QuestionName="与基线相比SOD变化量",QuestionType=QuestionType.SODChange}, + new ExportReportQuestion (){ QuestionName="与基线相比SOD变化百分比",QuestionType=QuestionType.SODPercent}, + new ExportReportQuestion (){ QuestionName="与最低点相比SOD变化量",QuestionType=QuestionType.LowestIncrease}, + new ExportReportQuestion (){ QuestionName="与最低点相比SOD变化百分比",QuestionType=QuestionType.LowPercent}, + new ExportReportQuestion (){ QuestionName="最低点访视",QuestionType=QuestionType.LowVisit}, + }; + + var isConvertedTask = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Select(x => x.IsConvertedTask).FirstOrDefaultAsync(); + + if (isConvertedTask) + { + resultList.AddRange(new List() + { new ExportReportQuestion (){ QuestionName="与触发iRECIST访视相比SOD变化量",QuestionType=QuestionType.ComparedTriggeringSODChange}, + new ExportReportQuestion (){ QuestionName="新靶病灶直径之和(iSOD)",QuestionType=QuestionType.ISOD}, + new ExportReportQuestion (){ QuestionName="与触发iRECIST访视相比iSOD变化量",QuestionType=QuestionType.ComparedTriggeringiSODChange}, + + }); + + } + + var assessmentResult = string.Empty; + if (visitInfo.IsBaseLine) + { + var existDisease = answerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.ExistDisease).Select(x => x.Answer).FirstIsNullReturnEmpty().EqEnum(ExistDisease.No) ? "不" : string.Empty; + assessmentResult = $"{existDisease}存在疾病"; + } + else + { + assessmentResult = $"整体肿瘤评估结果为{_generalCalculateService.GetTaskanswer(answerList, dictionList, unitDictionary, inDto.VisitTaskId, QuestionType.Tumor)}"; + } + var value = new Dictionary() + { + // { "Logo" ,await _generalCalculateService.GetWordPictureMaxWL(_options.CurrentValue.MinIO.viewEndpoint+_hospital.CurrentValue.HospitalLogoPath ,System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}"),110,100) }, + + { "HospitalName",_hospital.CurrentValue.HospitalName } ,// 医院名称 + { "SubjectName",subjectInfo.ShortName }, //患者姓名 + { "SubjectSex", subjectInfo.Sex==string.Empty?string.Empty: subjectInfo.Sex=="M"?"男":"女" }, //患者性别 + { "SubjectAge",subjectInfo.Age==null?string.Empty: subjectInfo.Age +"岁" }, //患者年龄 + { "SubjectCode",subjectPatientList.Select(x=>x.Patient).OrderByDescending(x=>x.CreateTime).Select(x=>x.PatientIdStr).FirstIsNullReturnEmpty() }, //患者编号 + { "VisitName",visitInfo.VisitName }, //访视名称 + { "LatestScanDate",visitInfo.StudyList.Min(x=>x.StudyTime)?.ToString("yyyy-MM-dd") }, //随访日期 + { "CriterionName",taskinfo.TrialReadingCriterion.CriterionName }, //评估标准 + { "AssessmentResult", assessmentResult }, //评估结果 + { "DoctorName",doctor.LastName + doctor.FirstName}, //医生姓名 + { "SignTime",taskinfo.SignTime?.ToString("yyyy-MM-dd HH:mm:ss") }, //签名时间 + { "StudyInfo",studyInfo }, // 检查信息 + { "FirstVisit", relatedVisitTask.Item1[0].TaskName}, + { "SecondVisit",relatedCount>=2?relatedVisitTask.Item1[1].TaskName:string.Empty}, + { "ThirdlyVisit", relatedCount>=3?relatedVisitTask.Item1[2].TaskName:string.Empty}, + + { "TargetInfo", getLesionInfo(LesionType.TargetLesion)}, // 靶病灶 + { "NoTargetInfo", getLesionInfo(LesionType.NonTargetLesions)}, // 非把病灶 + { "NewTargetInfo", getLesionInfo(LesionType.NewLesions)},// 新病灶 + { "NewITargetInfo", getLesionInfo(LesionType.NewTargetLesion)}, // 新靶病灶 + { "NewNoTargetInfo", getLesionInfo(LesionType.NewNonTargetLesion)}, // 新非靶病灶 + { "OtherPreviousNewInfo", getLesionInfo(LesionType.OtherPreviousNewLesion)}, // 其它既往新病灶 + { "TriggeringIRECSITInfo", getLesionInfo(LesionType.TriggeringIRECSIT)}, // 触发iRECSIT后的新病灶 + + + { "TargetImage", await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.TargetLesion,inDto.DownLoadGuid)}, // 靶病灶图片 + { "NoTargetImage",await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.NonTargetLesions,inDto.DownLoadGuid)}, // 非靶病灶图片 + { "NewImage", await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.NewLesions,inDto.DownLoadGuid)}, // 新病灶图片 + + { "NewITargetImage",await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.NewTargetLesion,inDto.DownLoadGuid)}, // 新靶病灶 + { "NewNoTargetImage",await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.NewNonTargetLesion,inDto.DownLoadGuid)}, // 新非靶病灶 + { "OtherPreviousNewImage", await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.OtherPreviousNewLesion,inDto.DownLoadGuid)}, // 其它既往新病灶 + { "TriggeringIRECSITImage",await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.TriggeringIRECSIT,inDto.DownLoadGuid)}, // 触发iRECSIT后的新病灶 + + + + + { "Result",getQuestionAnswerList(resultList)}, // 评估结果 + { "Curative",getQuestionAnswerList(new List() + { new ExportReportQuestion (){ QuestionName="靶病灶评估",QuestionType=QuestionType.TargetLesion}, + new ExportReportQuestion (){ QuestionName="非靶病灶评估",QuestionType=QuestionType.NoTargetLesion}, + new ExportReportQuestion (){ QuestionName="存在新病灶",QuestionType=QuestionType.NewLesions}, + new ExportReportQuestion (){ QuestionName="存在疾病",QuestionType=QuestionType.ExistDisease}, + new ExportReportQuestion (){ QuestionName="整体肿瘤评估",QuestionType=QuestionType.Tumor}, + })}, // 疗效结果 + + { "ReportNo",await _generalCalculateService.GetReportExportNo(taskinfo) } , + }; + + value = _generalCalculateService.StringEmptyTurnedLine(value); + + var templatePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/ReportTemplate_RECIST1.1_CN_V1.docx"); + if (isConvertedTask) + { + templatePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/ReportTemplate_IRECIST_CN_V1.docx"); + + } + var outputFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}.docx"); + MiniWord.SaveAsByTemplate(outputFilePath, templatePath, value); + Directory.Delete(downFile, true); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Stream stream = _generalCalculateService.ReadAndReturnStream(outputFilePath); + return stream; + } + else + { + var pdfurl = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/downLoad"); + FileConvertHelper.ConvertWordToPdf(outputFilePath, pdfurl); + Stream stream = _generalCalculateService.ReadAndReturnStream(pdfurl + $"/{inDto.DownLoadGuid}.pdf"); + return stream; + } + } + #region 临时对象 单个请求的生命周期 避免重复查询数据库 private List visitTaskAnswerList; diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/IVUSCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/IVUSCalculateService.cs index 37d479e9f..f28086782 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/IVUSCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/IVUSCalculateService.cs @@ -45,6 +45,16 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate }; } + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReportStream(DownLoadReadReportInDto inDto) + { + throw new BusinessValidationFailedException(_localizer["ReadingCalculate_DownLoadReadReport"]); + } + #region 临时对象 单个请求的生命周期 避免重复查询数据库 private List visitTaskAnswerList; diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/ICriterionCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/ICriterionCalculateService.cs index d5dc5048f..9086a7cdf 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/ICriterionCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/ICriterionCalculateService.cs @@ -55,6 +55,13 @@ namespace IRaCIS.Core.Application.Service Task GetReadingCalculationData(GetReadingCalculationDataInDto inDto); + /// + /// 下载阅片报告 + /// + /// + /// + Task DownLoadReadReportStream(DownLoadReadReportInDto inDto); + } diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IGeneralCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IGeneralCalculateService.cs index 9eaefec17..c1e57ca84 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IGeneralCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IGeneralCalculateService.cs @@ -1,6 +1,7 @@ using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Domain.Share; using Microsoft.AspNetCore.Http; +using MiniSoftware; using System.Data; namespace IRaCIS.Core.Application.Service @@ -45,5 +46,95 @@ namespace IRaCIS.Core.Application.Service /// /// Task GetDataTableFromUpload(IFormFile file, string pathCode, Guid trialId); + + /// + /// 获取图片 + /// + /// + /// + /// + /// + Task GetWordPicture(string url, string savePath, int width); + + /// + /// 获取图片 + /// + /// + /// + /// + /// + Task GetWordPicture(string url, string savePath, int width, int height); + + /// + /// 下载文件 + /// + /// + /// + /// + Task FileDownSave(string url, string savePath); + + /// + /// 获取并复制文件流 + /// + /// + /// + Stream ReadAndReturnStream(string outputFilePath); + + /// + /// 最大宽高 保持比例 + /// + /// + /// + /// + /// + /// + Task GetWordPictureMaxWL(string url, string savePath, int width, int height); + + /// + /// 空转为横线 + /// + /// + /// + Dictionary StringEmptyTurnedLine(Dictionary myDictionary); + + /// + /// 获取病灶的图片 rowinfoList要带question的信息 + /// + /// + /// + /// + /// + Task>> GetLesionPic(List rowinfoList, LesionType lesionType, Guid downLoadGuid); + + /// + /// 获取任务问题答案 + /// + /// 问题答案 + /// 字典数据 + /// 单位字典 + /// 任务Id + /// 任务类型 + /// + string GetTaskanswer(List? answerList, List? dictionList, List? unitDictionary, Guid taskId, QuestionType questionType); + + /// + /// 获取任务表格问题答案 + /// + /// 表格答案 + /// 字典 + /// 单位字典 + /// 任务Id + /// 病灶类型 + /// 问题标识 + /// 索引 + /// + string GetTaskTableAnswer(List? tableAnswerList, List? dictionList, List? unitDictionary, Guid taskId, LesionType lesionType, QuestionMark questionMark, decimal rowIndex); + + /// + /// 获取阅片报告 + /// + /// + /// + Task GetReportExportNo(VisitTask visitTaskInfo); } } diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs index 37449f651..c47890320 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/Interface/IReadingCalculateService.cs @@ -1,6 +1,7 @@ using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.ViewModel; using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; using System.Data; namespace IRaCIS.Core.Application.Service @@ -56,7 +57,28 @@ namespace IRaCIS.Core.Application.Service /// Task GetReadingCalculationData(GetReadingCalculationDataInDto inDto); - + + /// + /// 下载阅片报告 + /// + /// + /// + Task DownLoadReadReport(DownLoadReadReportInDto inDto); + + /// + /// 获取阅片报告流 + /// + /// + /// + Task DownLoadReadReportStream(DownLoadReadReportInDto inDto); + + /// + /// 获取并生成报告URl + /// + /// + /// + Task GetVisitReadReportUrl(CaGetVisitReadReportUrl inDto); + } } diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/LuganoCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/LuganoCalculateService.cs index c8a774a9d..8dff69f73 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/LuganoCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/LuganoCalculateService.cs @@ -55,6 +55,16 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate }; } + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReportStream(DownLoadReadReportInDto inDto) + { + throw new BusinessValidationFailedException(_localizer["ReadingCalculate_DownLoadReadReport"]); + } + #region 临时对象 单个请求的生命周期 避免重复查询数据库 private List visitTaskAnswerList; diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/LuganoWithoutPETCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/LuganoWithoutPETCalculateService.cs index e93bfa616..2bc4c7a52 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/LuganoWithoutPETCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/LuganoWithoutPETCalculateService.cs @@ -29,6 +29,16 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate IRepository _readingTaskQuestionAnswerRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ICriterionCalculateService, ILuganoCalculateService { + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReportStream(DownLoadReadReportInDto inDto) + { + throw new BusinessValidationFailedException(_localizer["ReadingCalculate_DownLoadReadReport"]); + } + /// /// 获取阅片的计算数据 /// diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/OCTCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/OCTCalculateService.cs index 1878f5413..f2d9daa97 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/OCTCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/OCTCalculateService.cs @@ -28,6 +28,15 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate IRepository _readingTaskQuestionAnswerRepository, ILogger _logger, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ICriterionCalculateService { + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReportStream(DownLoadReadReportInDto inDto) + { + throw new BusinessValidationFailedException(_localizer["ReadingCalculate_DownLoadReadReport"]); + } /// /// 获取阅片的计算数据 diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/PCWG3CalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/PCWG3CalculateService.cs index 27c8ccf4a..8eed15ecd 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/PCWG3CalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/PCWG3CalculateService.cs @@ -1,10 +1,17 @@ -using IRaCIS.Core.Application.Service.Reading.Dto; +using IRaCIS.Application.Contracts; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Helper; +using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore.Common; using IRaCIS.Core.Infrastructure; using MassTransit; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using MiniSoftware; +using System.Runtime.InteropServices; namespace IRaCIS.Core.Application.Service.ReadingCalculate { @@ -21,6 +28,12 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate IRepository _noneDicomStudyRepository, IRepository _tumorAssessmentRepository, IGeneralCalculateService _generalCalculateService, + IRepository _subjectRepository, + IRepository _userRepository, + IServiceProvider ServiceProvider, + IOptionsMonitor _hospital, + IRepository _dictionaryRepository, + IRepository _subjectPatientRepository, IRepository _readingTaskQuestionAnswerRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ICriterionCalculateService { @@ -39,6 +52,202 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate }; } + + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReportStream(DownLoadReadReportInDto inDto) + { + var downFile = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}"); + Directory.CreateDirectory(downFile); + var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId && x.ReadingCategory == ReadingCategory.Visit).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); + var visitInfo = await _subjectVisitRepository.Where(x => x.Id == taskinfo.SourceSubjectVisitId).Include(x => x.StudyList).FirstNotNullAsync(); + var subjectInfo = await _subjectRepository.Where(x => x.Id == taskinfo.SubjectId).Include(x => x.SubjectPatientList).FirstNotNullAsync(); + var doctor = await _userRepository.Where(x => x.Id == taskinfo.DoctorUserId).FirstOrDefaultAsync(); + + var trialQuestion = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).ToListAsync(); + var tableQuestion = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionTrial.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).ToListAsync(); + var dicotionCode = trialQuestion.Where(x => x.DictionaryCode != string.Empty).Select(x => x.DictionaryCode).Distinct().ToList(); + dicotionCode.AddRange(tableQuestion.Where(x => x.DictionaryCode != string.Empty).Select(x => x.DictionaryCode).Distinct()); + var dictionList = await _dictionaryRepository.Where(x => dicotionCode.Contains(x.Code)).Include(x => x.ChildList).ToListAsync(); + List taskIds = new List() { }; + var relatedVisitTask = await ServiceProvider.GetService().GetRelatedVisitTask(new GetRelatedVisitTaskInDto() + { + VisitTaskId = inDto.VisitTaskId + }); + + var relatedCount = relatedVisitTask.Item1.Count(); + + if (relatedCount <= 3) + { + taskIds = relatedVisitTask.Item1.Select(x => x.VisitTaskId).ToList(); + } + else + { + var count = relatedVisitTask.Item1.Count(); + taskIds.Add(relatedVisitTask.Item1[0].VisitTaskId); + taskIds.Add(relatedVisitTask.Item1[count - 2].VisitTaskId); + taskIds.Add(relatedVisitTask.Item1[count - 1].VisitTaskId); + + } + relatedVisitTask.Item1 = relatedVisitTask.Item1.Where(x => taskIds.Contains(x.VisitTaskId)).ToList(); + // 所有访视问题的答案 + var answerList = await _readingTaskQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.ReadingQuestionTrial).ToListAsync(); + + // 单位字典 + var unitDictionary = await _dictionaryRepository.Where(x => x.Code == "ValueUnit").Include(x => x.ChildList).ToListAsync(); + var imageProblem = _generalCalculateService.GetTaskanswer(answerList, dictionList, unitDictionary, inDto.VisitTaskId, QuestionType.ImageQualityAssessment); + var rowinfoList = await _readingTableAnswerRowInfoRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.VisitTask).Include(x => x.ReadingQuestionTrial).ToListAsync(); + var tableAnswerList = await _readingTableQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.ReadingQuestionTrial).Include(x => x.ReadingTableQuestionTrial).ToListAsync(); + + #region 获取各个病灶 + List> getLesionInfo(LesionType lesionType) + { + List targetFocusNum = rowinfoList.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionTrial.LesionType == lesionType).Select(x => x.RowIndex).OrderBy(x => x).ToList(); + + List> targetInfo = new List>(); + + foreach (var item in targetFocusNum) + { + var bodyPartDescription = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, inDto.VisitTaskId, lesionType, QuestionMark.BodyPartDescription, item); + Dictionary target = new Dictionary() + { + { "RowMark",rowinfoList.Where(x=>x.VisitTaskId == inDto.VisitTaskId &&x.RowIndex==item && x.ReadingQuestionTrial.LesionType == lesionType).Select(x=>x.RowMark).FirstIsNullReturnEmpty() }, + { "Organ",_generalCalculateService.GetTaskTableAnswer(tableAnswerList,dictionList,unitDictionary,inDto.VisitTaskId,lesionType,QuestionMark.Organ,item)+":"+_generalCalculateService.GetTaskTableAnswer(tableAnswerList,dictionList,unitDictionary,inDto.VisitTaskId,lesionType,QuestionMark.Part,item)+ (bodyPartDescription==string.Empty?string.Empty:","+bodyPartDescription) }, + { "FirstVisit",getStateInfo(0,item, lesionType) }, + { "SecondVisit", relatedCount>=2?getStateInfo(1,item,lesionType):string.Empty }, + { "ThirdlyVisit", relatedCount>=3?getStateInfo(2,item,lesionType):string.Empty }, + }; + targetInfo.Add(target); + } + return targetInfo; + } + + string getStateInfo(int index, decimal item, LesionType lesionType) + { + + var state = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.State, item); + var LesionNumber = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.LesionNumber, item); + var result = string.Empty; + + if (lesionType == LesionType.BaselineLesions) + { + return LesionNumber; + } + else + { + return state; + + } + } + + #endregion + + + #region 外层问题处理 + + // 获取外层问题 + List> getQuestionAnswerList(List exports) + { + List> questionAnswerList = new List>(); + foreach (var item in exports) + { + Dictionary questionAnswer = new Dictionary() + { + {"Name",item.QuestionName }, + {"FirstVisit", _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[0],item.QuestionType)}, + {"SecondVisit", relatedCount>=2? _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[1],item.QuestionType):string.Empty }, + {"ThirdlyVisit", relatedCount>=3? _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[2],item.QuestionType):string.Empty }, + }; + questionAnswerList.Add(questionAnswer); + } + return questionAnswerList; + } + + #endregion + + var studyInfo = (await _dicomStudyRepository.Where(x => x.SubjectVisitId == taskinfo.SourceSubjectVisitId).Select(x => new + { + + x.Modalities, + x.StudyTime, + x.BodyPartExamined, + x.Description + + }).OrderBy(x => x.StudyTime).ToListAsync()).Select(x => new Dictionary() { + + { "Modalities",x.Modalities}, + { "StudyTime",x.StudyTime?.ToString("yyyy-MM-dd")}, + { "Description",x.Description}, + { "ImageProblem",imageProblem}, + }).ToList(); + + + var subjectPatientList = await _subjectPatientRepository.Where(x => x.SubjectId == subjectInfo.Id).Include(x => x.Patient).ToListAsync(); + + + + var value = new Dictionary() + { + // { "Logo" ,await _generalCalculateService.GetWordPictureMaxWL(_options.CurrentValue.MinIO.viewEndpoint+_hospital.CurrentValue.HospitalLogoPath ,System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}"),110,100) }, + { "HospitalName",_hospital.CurrentValue.HospitalName } ,// 医院名称 + { "SubjectName",subjectInfo.ShortName }, //患者姓名 + { "SubjectSex", subjectInfo.Sex==string.Empty?string.Empty: subjectInfo.Sex=="M"?"男":"女" }, //患者性别 + { "SubjectAge",subjectInfo.Age==null?string.Empty: subjectInfo.Age +"岁" }, //患者年龄 + { "SubjectCode",subjectPatientList.Select(x=>x.Patient).OrderByDescending(x=>x.CreateTime).Select(x=>x.PatientIdStr).FirstIsNullReturnEmpty() }, //患者编号 + { "VisitName",visitInfo.VisitName }, //访视名称 + { "LatestScanDate",visitInfo.StudyList.Min(x=>x.StudyTime)?.ToString("yyyy-MM-dd") }, //随访日期 + { "CriterionName",taskinfo.TrialReadingCriterion.CriterionName }, //评估标准 + { "AssessmentResult", _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,inDto.VisitTaskId,QuestionType.SiteVisitForTumorEvaluation) }, //评估结果 + { "DoctorName",doctor.LastName + doctor.FirstName}, //医生姓名 + { "SignTime",taskinfo.SignTime?.ToString("yyyy-MM-dd HH:mm:ss") }, //签名时间 + { "StudyInfo",studyInfo }, // 检查信息 + { "FirstVisit", relatedVisitTask.Item1[0].TaskName}, + { "SecondVisit",relatedCount>=2?relatedVisitTask.Item1[1].TaskName:string.Empty}, + { "ThirdlyVisit", relatedCount>=3?relatedVisitTask.Item1[2].TaskName:string.Empty}, + { "BaselineLesionsInfo", getLesionInfo(LesionType.BaselineLesions)}, // 基线病灶 + { "AlwaysNewLesionsInfo", getLesionInfo(LesionType.AlwaysNewLesions)}, // 既往新病灶 + { "NewTargetInfo", getLesionInfo(LesionType.NewLesions)},// 新病灶 + { "BaselineLesionsImage", await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.BaselineLesions, inDto.DownLoadGuid)}, // 基线病灶 + { "AlwaysNewLesionsImage",await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.AlwaysNewLesions, inDto.DownLoadGuid)}, // 既往新病灶 + { "NewImage", await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.NewLesions, inDto.DownLoadGuid)}, // 新病灶图片 + { "Result",getQuestionAnswerList(new List() + { new ExportReportQuestion (){ QuestionName="基线病灶计数",QuestionType=QuestionType.BaseLineLesionsCount}, + new ExportReportQuestion (){ QuestionName="新病灶计数",QuestionType=QuestionType.NewLesionsCount}, + new ExportReportQuestion (){ QuestionName="既往新病灶计数",QuestionType=QuestionType.AlwaysNewLesionsCount}, + new ExportReportQuestion (){ QuestionName="自治疗后第二个访视点以来持续的新骨病变数量",QuestionType=QuestionType.NewBoneLesionsCount}, + new ExportReportQuestion (){ QuestionName="与前一个访视间隔天数",QuestionType=QuestionType.DaysBetween}, + })}, // 评估结果 + { "Curative",getQuestionAnswerList(new List() + { new ExportReportQuestion (){ QuestionName="访视点肿瘤评估",QuestionType=QuestionType.SiteVisitForTumorEvaluation}, + new ExportReportQuestion (){ QuestionName="访视阅片备注",QuestionType=QuestionType.AdjustReason}, + })}, // 疗效结果 + + { "ReportNo",await _generalCalculateService.GetReportExportNo(taskinfo) } , + }; + + value = _generalCalculateService.StringEmptyTurnedLine(value); + + var templatePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/ReportTemplate_PCWG3_CN_V1.docx"); + var outputFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}.docx"); + MiniWord.SaveAsByTemplate(outputFilePath, templatePath, value); + Directory.Delete(downFile, true); + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Stream stream = _generalCalculateService.ReadAndReturnStream(outputFilePath); + return stream; + } + else + { + var pdfurl = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/downLoad"); + FileConvertHelper.ConvertWordToPdf(outputFilePath, pdfurl); + Stream stream = _generalCalculateService.ReadAndReturnStream(pdfurl + $"/{inDto.DownLoadGuid}.pdf"); + return stream; + } + } + #region 删除病灶获取起始病灶序号 /// /// 删除病灶获取起始病灶序号 diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs index dfeb51bc0..3b1579c37 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1CalculateService.cs @@ -1,10 +1,17 @@ -using IRaCIS.Core.Application.Service.Reading.Dto; +using IRaCIS.Application.Contracts; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Helper; +using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore.Common; using IRaCIS.Core.Infrastructure; using MassTransit; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using MiniSoftware; +using System.Runtime.InteropServices; namespace IRaCIS.Core.Application.Service.ReadingCalculate { @@ -21,6 +28,13 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate IRepository _subjectVisitRepository, IRepository _tumorAssessmentRepository, IGeneralCalculateService _generalCalculateService, + IRepository _subjectRepository, + IRepository _userRepository, + IServiceProvider ServiceProvider, + IOptionsMonitor _hospital, + IRepository _dictionaryRepository, + IRepository _dicomStudyRepository, + IRepository _subjectPatientRepository, IRepository _readingTaskQuestionAnswerRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ICriterionCalculateService { @@ -36,6 +50,238 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate }; } + + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReportStream(DownLoadReadReportInDto inDto) + { + var downFile = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}"); + Directory.CreateDirectory(downFile); + var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId && x.ReadingCategory == ReadingCategory.Visit) + .Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); + var visitInfo = await _subjectVisitRepository.Where(x => x.Id == taskinfo.SourceSubjectVisitId).Include(x => x.StudyList).FirstNotNullAsync(); + var subjectInfo = await _subjectRepository.Where(x => x.Id == taskinfo.SubjectId).Include(x => x.SubjectPatientList).FirstNotNullAsync(); + var doctor = await _userRepository.Where(x => x.Id == taskinfo.DoctorUserId).FirstOrDefaultAsync(); + + var trialQuestion = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).ToListAsync(); + var tableQuestion = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionTrial.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).ToListAsync(); + var dicotionCode = trialQuestion.Where(x => x.DictionaryCode != string.Empty).Select(x => x.DictionaryCode).Distinct().ToList(); + dicotionCode.AddRange(tableQuestion.Where(x => x.DictionaryCode != string.Empty).Select(x => x.DictionaryCode).Distinct()); + var dictionList = await _dictionaryRepository.Where(x => dicotionCode.Contains(x.Code)).Include(x => x.ChildList).ToListAsync(); + List taskIds = new List() { }; + var relatedVisitTask = await ServiceProvider.GetService().GetRelatedVisitTask(new GetRelatedVisitTaskInDto() + { + VisitTaskId = inDto.VisitTaskId + }); + + var relatedCount = relatedVisitTask.Item1.Count(); + + if (relatedCount <= 3) + { + taskIds = relatedVisitTask.Item1.Select(x => x.VisitTaskId).ToList(); + } + else + { + var count = relatedVisitTask.Item1.Count(); + taskIds.Add(relatedVisitTask.Item1[0].VisitTaskId); + taskIds.Add(relatedVisitTask.Item1[count - 2].VisitTaskId); + taskIds.Add(relatedVisitTask.Item1[count - 1].VisitTaskId); + + } + relatedVisitTask.Item1 = relatedVisitTask.Item1.Where(x => taskIds.Contains(x.VisitTaskId)).ToList(); + // 所有访视问题的答案 + var answerList = await _readingTaskQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.ReadingQuestionTrial).ToListAsync(); + + // 单位字典 + var unitDictionary = await _dictionaryRepository.Where(x => x.Code == "ValueUnit").Include(x => x.ChildList).ToListAsync(); + var imageProblem = _generalCalculateService.GetTaskanswer(answerList, dictionList, unitDictionary, inDto.VisitTaskId, QuestionType.ImageQualityAssessment); + var rowinfoList = await _readingTableAnswerRowInfoRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.VisitTask).Include(x => x.ReadingQuestionTrial).ToListAsync(); + var tableAnswerList = await _readingTableQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.ReadingQuestionTrial).Include(x => x.ReadingTableQuestionTrial).ToListAsync(); + + #region 获取各个病灶 + List> getLesionInfo(LesionType lesionType) + { + List targetFocusNum = rowinfoList.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionTrial.LesionType == lesionType).Select(x => x.RowIndex).OrderBy(x => x).ToList(); + + List> targetInfo = new List>(); + + foreach (var item in targetFocusNum) + { + var bodyPartDescription = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, inDto.VisitTaskId, lesionType, QuestionMark.BodyPartDescription, item); + Dictionary target = new Dictionary() + { + { "RowMark",rowinfoList.Where(x=>x.VisitTaskId == inDto.VisitTaskId &&x.RowIndex==item && x.ReadingQuestionTrial.LesionType == lesionType).Select(x=>x.RowMark).FirstIsNullReturnEmpty() }, + { "Organ",_generalCalculateService.GetTaskTableAnswer(tableAnswerList,dictionList,unitDictionary,inDto.VisitTaskId,lesionType,QuestionMark.Organ,item)+":"+_generalCalculateService.GetTaskTableAnswer(tableAnswerList,dictionList,unitDictionary,inDto.VisitTaskId,lesionType,QuestionMark.Part,item)+ (bodyPartDescription==string.Empty?string.Empty:","+bodyPartDescription) }, + { "FirstVisit",getStateInfo(0,item, lesionType) }, + { "SecondVisit", relatedCount>=2?getStateInfo(1,item,lesionType):string.Empty }, + { "ThirdlyVisit", relatedCount>=3?getStateInfo(2,item,lesionType):string.Empty }, + }; + targetInfo.Add(target); + } + return targetInfo; + } + + string getStateInfo(int index, decimal item, LesionType lesionType) + { + // 非淋巴结取长径 淋巴结取长短径 + var state = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.State, item); + var majorAxis = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.MajorAxis, item); + + var isLymph = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.IsLymph, item); + var shortAxis = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.ShortAxis, item); + + var result = string.Empty; + + if (!state.IsNullOrEmpty()) + { + result = state; + + } + + if (!majorAxis.IsNullOrEmpty()) + { + result += result == string.Empty ? $"L:{majorAxis}" : $",L:{majorAxis}"; + } + + if (isLymph.EqEnum(YesOrNoOrNa.Yes) && !shortAxis.IsNullOrEmpty()) + { + result += result == string.Empty ? $"S:{shortAxis}" : $",S:{shortAxis}"; + } + + return result; + + } + + #endregion + + + #region 外层问题处理 + + // 获取外层问题 + List> getQuestionAnswerList(List exports) + { + List> questionAnswerList = new List>(); + foreach (var item in exports) + { + Dictionary questionAnswer = new Dictionary() + { + {"Name",item.QuestionName }, + {"FirstVisit", _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[0],item.QuestionType)}, + {"SecondVisit", relatedCount>=2? _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[1],item.QuestionType):string.Empty }, + {"ThirdlyVisit", relatedCount>=3? _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[2],item.QuestionType):string.Empty }, + }; + questionAnswerList.Add(questionAnswer); + } + return questionAnswerList; + } + + #endregion + + var studyInfo = (await _dicomStudyRepository.Where(x => x.SubjectVisitId == taskinfo.SourceSubjectVisitId).Select(x => new + { + + x.Modalities, + x.StudyTime, + x.BodyPartExamined, + x.Description + + }).OrderBy(x => x.StudyTime).ToListAsync()).Select(x => new Dictionary() { + + { "Modalities",x.Modalities}, + { "StudyTime",x.StudyTime?.ToString("yyyy-MM-dd")}, + { "Description",x.Description}, + { "ImageProblem",imageProblem}, + }).ToList(); + + + var subjectPatientList = await _subjectPatientRepository.Where(x => x.SubjectId == subjectInfo.Id).Include(x => x.Patient).ToListAsync(); + + var assessmentResult = string.Empty; + if (visitInfo.IsBaseLine) + { + var existDisease = answerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.ExistDisease).Select(x => x.Answer).FirstIsNullReturnEmpty().EqEnum(ExistDisease.No) ? "不" : string.Empty; + assessmentResult = $"{existDisease}存在疾病"; + } + else + { + assessmentResult = $"整体肿瘤评估结果为{_generalCalculateService.GetTaskanswer(answerList, dictionList, unitDictionary, inDto.VisitTaskId, QuestionType.Tumor)}"; + } + + var value = new Dictionary() + { + // { "Logo" ,await _generalCalculateService.GetWordPictureMaxWL(_options.CurrentValue.MinIO.viewEndpoint+_hospital.CurrentValue.HospitalLogoPath ,System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}"),110,100) }, + + { "HospitalName",_hospital.CurrentValue.HospitalName } ,// 医院名称 + { "SubjectName",subjectInfo.ShortName }, //患者姓名 + { "SubjectSex", subjectInfo.Sex==string.Empty?string.Empty: subjectInfo.Sex=="M"?"男":"女" }, //患者性别 + { "SubjectAge",subjectInfo.Age==null?string.Empty: subjectInfo.Age +"岁" }, //患者年龄 + { "SubjectCode",subjectPatientList.Select(x=>x.Patient).OrderByDescending(x=>x.CreateTime).Select(x=>x.PatientIdStr).FirstIsNullReturnEmpty() }, //患者编号 + { "VisitName",visitInfo.VisitName }, //访视名称 + { "LatestScanDate",visitInfo.StudyList.Min(x=>x.StudyTime)?.ToString("yyyy-MM-dd") }, //随访日期 + { "CriterionName",taskinfo.TrialReadingCriterion.CriterionName }, //评估标准 + { "AssessmentResult", assessmentResult }, //评估结果 + { "DoctorName",doctor.LastName + doctor.FirstName}, //医生姓名 + { "SignTime",taskinfo.SignTime?.ToString("yyyy-MM-dd HH:mm:ss") }, //签名时间 + { "StudyInfo",studyInfo }, // 检查信息 + { "FirstVisit", relatedVisitTask.Item1[0].TaskName}, + { "SecondVisit",relatedCount>=2?relatedVisitTask.Item1[1].TaskName:string.Empty}, + { "ThirdlyVisit", relatedCount>=3?relatedVisitTask.Item1[2].TaskName:string.Empty}, + { "TargetInfo", getLesionInfo(LesionType.TargetLesion)}, // 靶病灶 + { "NoTargetInfo", getLesionInfo(LesionType.NonTargetLesions)}, // 非把病灶 + { "NewTargetInfo", getLesionInfo(LesionType.NewLesions)},// 新病灶 + { "TargetImage", await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.TargetLesion,inDto.DownLoadGuid)}, // 靶病灶图片 + { "NoTargetImage",await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.NonTargetLesions,inDto.DownLoadGuid)}, // 非靶病灶图片 + { "NewImage", await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.NewLesions,inDto.DownLoadGuid)}, // 新病灶图片 + { "Result",getQuestionAnswerList(new List() + { new ExportReportQuestion (){ QuestionName="靶病灶径线之和(SOD)",QuestionType=QuestionType.SOD}, + new ExportReportQuestion (){ QuestionName="非淋巴结靶病灶长径之和",QuestionType=QuestionType.SumOfDiameter}, + new ExportReportQuestion (){ QuestionName="与基线相比SOD变化量",QuestionType=QuestionType.SODChange}, + new ExportReportQuestion (){ QuestionName="与基线相比SOD变化百分比",QuestionType=QuestionType.SODPercent}, + new ExportReportQuestion (){ QuestionName="与最低点相比SOD变化量",QuestionType=QuestionType.LowestIncrease}, + new ExportReportQuestion (){ QuestionName="与最低点相比SOD变化百分比",QuestionType=QuestionType.LowPercent}, + new ExportReportQuestion (){ QuestionName="最低点访视",QuestionType=QuestionType.LowVisit}, + })}, // 评估结果 + { "Curative",getQuestionAnswerList(new List() + { new ExportReportQuestion (){ QuestionName="靶病灶评估",QuestionType=QuestionType.TargetLesion}, + new ExportReportQuestion (){ QuestionName="非靶病灶评估",QuestionType=QuestionType.NoTargetLesion}, + new ExportReportQuestion (){ QuestionName="存在新病灶",QuestionType=QuestionType.NewLesions}, + new ExportReportQuestion (){ QuestionName="存在疾病",QuestionType=QuestionType.ExistDisease}, + new ExportReportQuestion (){ QuestionName="整体肿瘤评估",QuestionType=QuestionType.Tumor}, + })}, // 疗效结果 + + { "ReportNo",await _generalCalculateService.GetReportExportNo(taskinfo) } , + }; + + value = _generalCalculateService.StringEmptyTurnedLine(value); + + var templatePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/ReportTemplate_RECIST1.1_CN_V1.docx"); + var outputFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}.docx"); + + + MiniWord.SaveAsByTemplate(outputFilePath, templatePath, value); + + + //// 获取文件夹中的所有文件路径 + Directory.Delete(downFile, true); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Stream stream = _generalCalculateService.ReadAndReturnStream(outputFilePath); + return stream; + } + else + { + + var pdfurl = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/downLoad"); + FileConvertHelper.ConvertWordToPdf(outputFilePath, pdfurl); + Stream stream = _generalCalculateService.ReadAndReturnStream(pdfurl + $"/{inDto.DownLoadGuid}.pdf"); + return stream; + } + } + #region 临时对象 单个请求的生命周期 避免重复查询数据库 private List visitTaskAnswerList; diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1_BMCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1_BMCalculateService.cs index 70e446434..bd02df1ff 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1_BMCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/RECIST1Point1_BMCalculateService.cs @@ -1,10 +1,18 @@ -using IRaCIS.Core.Application.Service.Reading.Dto; +using IRaCIS.Application.Contracts; +using IRaCIS.Core.Application.Contracts; +using IRaCIS.Core.Application.Helper; +using IRaCIS.Core.Application.Service.Reading.Dto; using IRaCIS.Core.Application.ViewModel; +using IRaCIS.Core.Domain.Models; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore.Common; using IRaCIS.Core.Infrastructure; using MassTransit; using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using MiniSoftware; +using System.Runtime.InteropServices; namespace IRaCIS.Core.Application.Service.ReadingCalculate { @@ -21,6 +29,13 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate IRepository _subjectVisitRepository, IRepository _tumorAssessment_RECIST1Point1BM, IGeneralCalculateService _generalCalculateService, + IRepository _subjectRepository, + IRepository _userRepository, + IServiceProvider ServiceProvider, + IOptionsMonitor _hospital, + IRepository _dictionaryRepository, + IRepository _dicomStudyRepository, + IRepository _subjectPatientRepository, IRepository _readingTaskQuestionAnswerRepository, IMapper _mapper, IUserInfo _userInfo, IStringLocalizer _localizer) : BaseService, ICriterionCalculateService { @@ -36,6 +51,236 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate }; } + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReportStream(DownLoadReadReportInDto inDto) + { + var downFile = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}"); + Directory.CreateDirectory(downFile); + var taskinfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId && x.ReadingCategory == ReadingCategory.Visit).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); + var visitInfo = await _subjectVisitRepository.Where(x => x.Id == taskinfo.SourceSubjectVisitId).Include(x => x.StudyList).FirstNotNullAsync(); + var subjectInfo = await _subjectRepository.Where(x => x.Id == taskinfo.SubjectId).Include(x => x.SubjectPatientList).FirstNotNullAsync(); + var doctor = await _userRepository.Where(x => x.Id == taskinfo.DoctorUserId).FirstOrDefaultAsync(); + + var trialQuestion = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).ToListAsync(); + var tableQuestion = await _readingTableQuestionTrialRepository.Where(x => x.ReadingQuestionTrial.ReadingQuestionCriterionTrialId == taskinfo.TrialReadingCriterionId).ToListAsync(); + var dicotionCode = trialQuestion.Where(x => x.DictionaryCode != string.Empty).Select(x => x.DictionaryCode).Distinct().ToList(); + dicotionCode.AddRange(tableQuestion.Where(x => x.DictionaryCode != string.Empty).Select(x => x.DictionaryCode).Distinct()); + var dictionList = await _dictionaryRepository.Where(x => dicotionCode.Contains(x.Code)).Include(x => x.ChildList).ToListAsync(); + List taskIds = new List() { }; + var relatedVisitTask = await ServiceProvider.GetService().GetRelatedVisitTask(new GetRelatedVisitTaskInDto() + { + VisitTaskId = inDto.VisitTaskId + }); + + var relatedCount = relatedVisitTask.Item1.Count(); + + if (relatedCount <= 3) + { + taskIds = relatedVisitTask.Item1.Select(x => x.VisitTaskId).ToList(); + } + else + { + var count = relatedVisitTask.Item1.Count(); + taskIds.Add(relatedVisitTask.Item1[0].VisitTaskId); + taskIds.Add(relatedVisitTask.Item1[count - 2].VisitTaskId); + taskIds.Add(relatedVisitTask.Item1[count - 1].VisitTaskId); + + } + relatedVisitTask.Item1 = relatedVisitTask.Item1.Where(x => taskIds.Contains(x.VisitTaskId)).ToList(); + // 所有访视问题的答案 + var answerList = await _readingTaskQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.ReadingQuestionTrial).ToListAsync(); + + // 单位字典 + var unitDictionary = await _dictionaryRepository.Where(x => x.Code == "ValueUnit").Include(x => x.ChildList).ToListAsync(); + var imageProblem = _generalCalculateService.GetTaskanswer(answerList, dictionList, unitDictionary, inDto.VisitTaskId, QuestionType.ImageQualityAssessment); + var rowinfoList = await _readingTableAnswerRowInfoRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.VisitTask).Include(x => x.ReadingQuestionTrial).ToListAsync(); + var tableAnswerList = await _readingTableQuestionAnswerRepository.Where(x => taskIds.Contains(x.VisitTaskId)).Include(x => x.ReadingQuestionTrial).Include(x => x.ReadingTableQuestionTrial).ToListAsync(); + + #region 获取各个病灶 + List> getLesionInfo(LesionType lesionType) + { + List targetFocusNum = rowinfoList.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.ReadingQuestionTrial.LesionType == lesionType).Select(x => x.RowIndex).OrderBy(x => x).ToList(); + + List> targetInfo = new List>(); + + foreach (var item in targetFocusNum) + { + var bodyPartDescription = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, inDto.VisitTaskId, lesionType, QuestionMark.BodyPartDescription, item); + Dictionary target = new Dictionary() + { + { "RowMark",rowinfoList.Where(x=>x.VisitTaskId == inDto.VisitTaskId &&x.RowIndex==item && x.ReadingQuestionTrial.LesionType == lesionType).Select(x=>x.RowMark).FirstIsNullReturnEmpty() }, + { "Organ",_generalCalculateService.GetTaskTableAnswer(tableAnswerList,dictionList,unitDictionary,inDto.VisitTaskId,lesionType,QuestionMark.Organ,item)+":"+_generalCalculateService.GetTaskTableAnswer(tableAnswerList,dictionList,unitDictionary,inDto.VisitTaskId,lesionType,QuestionMark.Part,item)+ (bodyPartDescription==string.Empty?string.Empty:","+bodyPartDescription) }, + { "FirstVisit",getStateInfo(0,item, lesionType) }, + { "SecondVisit", relatedCount>=2?getStateInfo(1,item,lesionType):string.Empty }, + { "ThirdlyVisit", relatedCount>=3?getStateInfo(2,item,lesionType):string.Empty }, + }; + targetInfo.Add(target); + } + return targetInfo; + } + + string getStateInfo(int index, decimal item, LesionType lesionType) + { + // 非淋巴结取长径 淋巴结取长短径 + var state = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.State, item); + var majorAxis = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.MajorAxis, item); + + var isLymph = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.IsLymph, item); + var shortAxis = _generalCalculateService.GetTaskTableAnswer(tableAnswerList, dictionList, unitDictionary, taskIds[index], lesionType, QuestionMark.ShortAxis, item); + + var result = string.Empty; + + if (!state.IsNullOrEmpty()) + { + result = state; + + } + + if (!majorAxis.IsNullOrEmpty()) + { + result += result == string.Empty ? $"L:{majorAxis}" : $",L:{majorAxis}"; + } + + if (isLymph.EqEnum(YesOrNoOrNa.Yes) && !shortAxis.IsNullOrEmpty()) + { + result += result == string.Empty ? $"S:{shortAxis}" : $",S:{shortAxis}"; + } + + return result; + + } + + #endregion + + + #region 外层问题处理 + + // 获取外层问题 + List> getQuestionAnswerList(List exports) + { + List> questionAnswerList = new List>(); + foreach (var item in exports) + { + Dictionary questionAnswer = new Dictionary() + { + {"Name",item.QuestionName }, + {"FirstVisit", _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[0],item.QuestionType)}, + {"SecondVisit", relatedCount>=2? _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[1],item.QuestionType):string.Empty }, + {"ThirdlyVisit", relatedCount>=3? _generalCalculateService.GetTaskanswer(answerList,dictionList,unitDictionary,taskIds[2],item.QuestionType):string.Empty }, + }; + questionAnswerList.Add(questionAnswer); + } + return questionAnswerList; + } + + #endregion + + var studyInfo = (await _dicomStudyRepository.Where(x => x.SubjectVisitId == taskinfo.SourceSubjectVisitId).Select(x => new + { + + x.Modalities, + x.StudyTime, + x.BodyPartExamined, + x.Description + + }).OrderBy(x => x.StudyTime).ToListAsync()).Select(x => new Dictionary() { + + { "Modalities",x.Modalities}, + { "StudyTime",x.StudyTime?.ToString("yyyy-MM-dd")}, + { "Description",x.Description}, + { "ImageProblem",imageProblem}, + }).ToList(); + + + var subjectPatientList = await _subjectPatientRepository.Where(x => x.SubjectId == subjectInfo.Id).Include(x => x.Patient).ToListAsync(); + + var assessmentResult = string.Empty; + if (visitInfo.IsBaseLine) + { + var existDisease = answerList.Where(x => x.ReadingQuestionTrial.QuestionType == QuestionType.ExistDisease).Select(x => x.Answer).FirstIsNullReturnEmpty().EqEnum(ExistDisease.No) ? "不" : string.Empty; + assessmentResult = $"{existDisease}存在疾病"; + } + else + { + assessmentResult = $"整体肿瘤评估结果为{_generalCalculateService.GetTaskanswer(answerList, dictionList, unitDictionary, inDto.VisitTaskId, QuestionType.Tumor)}"; + } + + var value = new Dictionary() + { + // { "Logo" ,await _generalCalculateService.GetWordPictureMaxWL(_options.CurrentValue.MinIO.viewEndpoint+_hospital.CurrentValue.HospitalLogoPath ,System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}"),110,100) }, + + { "HospitalName",_hospital.CurrentValue.HospitalName } ,// 医院名称 + { "SubjectName",subjectInfo.ShortName }, //患者姓名 + { "SubjectSex", subjectInfo.Sex==string.Empty?string.Empty: subjectInfo.Sex=="M"?"男":"女" }, //患者性别 + { "SubjectAge",subjectInfo.Age==null?string.Empty: subjectInfo.Age +"岁" }, //患者年龄 + { "SubjectCode",subjectPatientList.Select(x=>x.Patient).OrderByDescending(x=>x.CreateTime).Select(x=>x.PatientIdStr).FirstIsNullReturnEmpty() }, //患者编号 + { "VisitName",visitInfo.VisitName }, //访视名称 + { "LatestScanDate",visitInfo.StudyList.Min(x=>x.StudyTime)?.ToString("yyyy-MM-dd") }, //随访日期 + { "CriterionName",taskinfo.TrialReadingCriterion.CriterionName }, //评估标准 + { "AssessmentResult", assessmentResult }, //评估结果 + { "DoctorName",doctor.LastName + doctor.FirstName}, //医生姓名 + { "SignTime",taskinfo.SignTime?.ToString("yyyy-MM-dd HH:mm:ss") }, //签名时间 + { "StudyInfo",studyInfo }, // 检查信息 + { "FirstVisit", relatedVisitTask.Item1[0].TaskName}, + { "SecondVisit",relatedCount>=2?relatedVisitTask.Item1[1].TaskName:string.Empty}, + { "ThirdlyVisit", relatedCount>=3?relatedVisitTask.Item1[2].TaskName:string.Empty}, + { "TargetInfo", getLesionInfo(LesionType.TargetLesion)}, // 靶病灶 + { "NoTargetInfo", getLesionInfo(LesionType.NonTargetLesions)}, // 非把病灶 + { "NewTargetInfo", getLesionInfo(LesionType.NewLesions)},// 新病灶 + { "TargetImage", await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.TargetLesion,inDto.DownLoadGuid)}, // 靶病灶图片 + { "NoTargetImage",await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.NonTargetLesions,inDto.DownLoadGuid)}, // 非靶病灶图片 + { "NewImage", await _generalCalculateService.GetLesionPic(rowinfoList, LesionType.NewLesions,inDto.DownLoadGuid)}, // 新病灶图片 + { "Result",getQuestionAnswerList(new List() + { new ExportReportQuestion (){ QuestionName="靶病灶径线之和(SOD)",QuestionType=QuestionType.SOD}, + new ExportReportQuestion (){ QuestionName="非淋巴结靶病灶长径之和",QuestionType=QuestionType.SumOfDiameter}, + new ExportReportQuestion (){ QuestionName="与基线相比SOD变化量",QuestionType=QuestionType.SODChange}, + new ExportReportQuestion (){ QuestionName="与基线相比SOD变化百分比",QuestionType=QuestionType.SODPercent}, + new ExportReportQuestion (){ QuestionName="与最低点相比SOD变化量",QuestionType=QuestionType.LowestIncrease}, + new ExportReportQuestion (){ QuestionName="与最低点相比SOD变化百分比",QuestionType=QuestionType.LowPercent}, + new ExportReportQuestion (){ QuestionName="最低点访视",QuestionType=QuestionType.LowVisit}, + })}, // 评估结果 + { "Curative",getQuestionAnswerList(new List() + { new ExportReportQuestion (){ QuestionName="靶病灶评估",QuestionType=QuestionType.TargetLesion}, + new ExportReportQuestion (){ QuestionName="非靶病灶评估",QuestionType=QuestionType.NoTargetLesion}, + new ExportReportQuestion (){ QuestionName="存在新病灶",QuestionType=QuestionType.NewLesions}, + new ExportReportQuestion (){ QuestionName="存在疾病",QuestionType=QuestionType.ExistDisease}, + new ExportReportQuestion (){ QuestionName="整体肿瘤评估",QuestionType=QuestionType.Tumor}, + })}, // 疗效结果 + + { "ReportNo",await _generalCalculateService.GetReportExportNo(taskinfo) } , + }; + + value = _generalCalculateService.StringEmptyTurnedLine(value); + + var templatePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/ReportTemplate_RECIST1.1_CN_V1.docx"); + var outputFilePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $@"wwwroot/ReadReoprtTemplate/downLoad/{inDto.DownLoadGuid}.docx"); + + + MiniWord.SaveAsByTemplate(outputFilePath, templatePath, value); + + + //// 获取文件夹中的所有文件路径 + Directory.Delete(downFile, true); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + Stream stream = _generalCalculateService.ReadAndReturnStream(outputFilePath); + return stream; + } + else + { + + var pdfurl = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"wwwroot/ReadReoprtTemplate/downLoad"); + FileConvertHelper.ConvertWordToPdf(outputFilePath, pdfurl); + Stream stream = _generalCalculateService.ReadAndReturnStream(pdfurl + $"/{inDto.DownLoadGuid}.pdf"); + return stream; + } + } + #region 临时对象 单个请求的生命周期 避免重复查询数据库 private List visitTaskAnswerList; diff --git a/IRaCIS.Core.Application/Service/ReadingCalculate/SelfDefineCalculateService.cs b/IRaCIS.Core.Application/Service/ReadingCalculate/SelfDefineCalculateService.cs index c8b2d5060..465775d3e 100644 --- a/IRaCIS.Core.Application/Service/ReadingCalculate/SelfDefineCalculateService.cs +++ b/IRaCIS.Core.Application/Service/ReadingCalculate/SelfDefineCalculateService.cs @@ -2,6 +2,7 @@ using IRaCIS.Core.Application.ViewModel; using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Infra.EFCore.Common; +using IRaCIS.Core.Infrastructure; using MassTransit; using Microsoft.AspNetCore.Mvc; @@ -25,6 +26,16 @@ namespace IRaCIS.Core.Application.Service.ReadingCalculate { + /// + /// 下载阅片报告 + /// + /// + /// + public async Task DownLoadReadReportStream(DownLoadReadReportInDto inDto) + { + throw new BusinessValidationFailedException(_localizer["ReadingCalculate_DownLoadReadReport"]); + } + private List siteVisitForTumorList = new List(); ///