From 1bb0c527735da00106609edaf7ea253d1bccf65a Mon Sep 17 00:00:00 2001 From: hang <872297557@qq.com> Date: Thu, 27 Oct 2022 14:40:15 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=82=AE=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 + IRaCIS.Core.API/IRaCIS.Core.API.csproj | 22 +- .../IRaCIS.Core.Application.csproj | 26 +- .../IRaCIS.Core.Application.xml | 7 +- .../Service/Allocation/VisitTaskService.cs | 6 +- .../Service/Common/CommonDocumentService.cs | 42 +- .../DTO/TrialEmailNoticeConfigViewModel.cs | 25 +- .../ITrialEmailNoticeConfigService.cs | 7 +- .../Document/TrialEmailNoticeConfigService.cs | 384 ++++++++++-------- .../Service/Document/_MapConfig.cs | 5 +- .../Dto/ReadingMedicineQuestionViewModel.cs | 2 +- .../ReadingMedicineQuestionService.cs | 5 +- .../ReadingImageTaskService.cs | 231 ++++++++++- .../Common/EmailScenarioEnum.cs | 2 + .../Document/TrialEmailNoticeUser.cs | 4 +- IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj | 4 +- .../IRaCIS.Core.Infra.EFCore.csproj | 2 +- .../IRaCIS.Core.Infrastructure.csproj | 4 +- IRaCISData/新建 DOCX 文档.docx | Bin 10114 -> 0 bytes 19 files changed, 514 insertions(+), 268 deletions(-) delete mode 100644 IRaCISData/新建 DOCX 文档.docx diff --git a/.gitignore b/.gitignore index 588b92b8..94b54ccd 100644 --- a/.gitignore +++ b/.gitignore @@ -367,3 +367,7 @@ FodyWeavers.xsd /TrialData/2a864970-1832-4cf9-f3ab-08da0cd341a0/01a4d468-caa4-41a2-ab36-c42ba30130ac/3210c828-cf32-4a70-fa40-08da0cd72d16/9a3b5449-ac01-4df1-bf24-08da0cd72d2a/Dicom/d287dde0-b9d1-9b37-28bb-371b6a445cf1 TrialData /IRaCIS.Core.Application/IRaCIS.Core.Application.xml + + +IRaCISData +UploadFile diff --git a/IRaCIS.Core.API/IRaCIS.Core.API.csproj b/IRaCIS.Core.API/IRaCIS.Core.API.csproj index e4fd66a8..0144ce82 100644 --- a/IRaCIS.Core.API/IRaCIS.Core.API.csproj +++ b/IRaCIS.Core.API/IRaCIS.Core.API.csproj @@ -67,24 +67,24 @@ - - - - - - - + + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + - + diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj index 61cb9868..3339706c 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.csproj @@ -62,10 +62,10 @@ - + - + @@ -76,22 +76,22 @@ true - - + + true - + true - - - - - + + + + + true - - + + true @@ -102,7 +102,7 @@ - + diff --git a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml index 114cd421..03724d59 100644 --- a/IRaCIS.Core.Application/IRaCIS.Core.Application.xml +++ b/IRaCIS.Core.Application/IRaCIS.Core.Application.xml @@ -402,18 +402,15 @@ - + 测试邮件 带附件 填充word --前端不需要用 - - - - + 选择人员下拉 diff --git a/IRaCIS.Core.Application/Service/Allocation/VisitTaskService.cs b/IRaCIS.Core.Application/Service/Allocation/VisitTaskService.cs index 3e7d3cd8..79e55c6b 100644 --- a/IRaCIS.Core.Application/Service/Allocation/VisitTaskService.cs +++ b/IRaCIS.Core.Application/Service/Allocation/VisitTaskService.cs @@ -62,9 +62,11 @@ namespace IRaCIS.Core.Application.Service.Allocation } - public async Task> GetTrialCriterionList(Guid trialId) + public async Task> GetTrialCriterionList(Guid trialId,bool isHaveSigned=true) { - var list = await _repository.Where(t => t.TrialId == trialId && t.IsConfirm).OrderBy(t => t.ShowOrder) + var list = await _repository.Where(t => t.TrialId == trialId && t.IsConfirm) + .WhereIf(isHaveSigned=true,t=>t.ReadingInfoSignTime!=null) + .OrderBy(t => t.ShowOrder) .Select(t => new TrialReadingCriterionDto() { TrialReadingCriterionId = t.Id, TrialReadingCriterionName = t.CriterionName, CriterionType = t.CriterionType, ReadingType = t.ReadingType }) .ToListAsync(); diff --git a/IRaCIS.Core.Application/Service/Common/CommonDocumentService.cs b/IRaCIS.Core.Application/Service/Common/CommonDocumentService.cs index 42342225..296f987d 100644 --- a/IRaCIS.Core.Application/Service/Common/CommonDocumentService.cs +++ b/IRaCIS.Core.Application/Service/Common/CommonDocumentService.cs @@ -8,6 +8,8 @@ using IRaCIS.Core.Domain.Models; using Microsoft.AspNetCore.Mvc; using IRaCIS.Core.Application.Interfaces; using IRaCIS.Core.Application.ViewModel; +using IRaCIS.Core.Application.Helper; + namespace IRaCIS.Core.Application.Service { /// @@ -32,11 +34,11 @@ namespace IRaCIS.Core.Application.Service var commonDocumentQueryable = _commonDocumentRepository.AsQueryable(true) .WhereIf(queryCommonDocument.FileTypeEnum != null, t => t.FileTypeEnum == queryCommonDocument.FileTypeEnum) - .WhereIf( queryCommonDocument.CriterionTypeEnum!=null ,t=>t.CriterionTypeEnum == queryCommonDocument.CriterionTypeEnum) + .WhereIf(queryCommonDocument.CriterionTypeEnum != null, t => t.CriterionTypeEnum == queryCommonDocument.CriterionTypeEnum) .WhereIf(queryCommonDocument.BusinessScenarioEnum != null, t => t.BusinessScenarioEnum == queryCommonDocument.BusinessScenarioEnum) - .WhereIf( string.IsNullOrEmpty(queryCommonDocument.Code) , t => t.Code.Contains(queryCommonDocument.Code) ) + .WhereIf(string.IsNullOrEmpty(queryCommonDocument.Code), t => t.Code.Contains(queryCommonDocument.Code)) .WhereIf(string.IsNullOrEmpty(queryCommonDocument.Name), t => t.Name.Contains(queryCommonDocument.Name)) - .ProjectTo(_mapper.ConfigurationProvider,new { token = _userInfo.UserToken, userId = _userInfo.Id }); + .ProjectTo(_mapper.ConfigurationProvider, new { token = _userInfo.UserToken, userId = _userInfo.Id }); return await commonDocumentQueryable.ToPagedListAsync(queryCommonDocument.PageIndex, queryCommonDocument.PageSize, String.IsNullOrEmpty(queryCommonDocument.SortField) ? nameof(CommonDocument.Code) : queryCommonDocument.SortField, queryCommonDocument.Asc); ; } @@ -50,6 +52,40 @@ namespace IRaCIS.Core.Application.Service VerifyMsg = "文档的Code不能够重复。" }; + + if (addOrEditCommonDocument.CriterionTypeEnum != null && addOrEditCommonDocument.CriterionTypeEnum != Domain.Share.CriterionType.NoCriterion) + { + var testValue = new Dictionary() + { + ["SponsorName"] = "Test", + }; + + var templatePhyicalPath = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, addOrEditCommonDocument.Path); + + + if (File.Exists(templatePhyicalPath)) + { + + try + { + MemoryStream memoryStream = new MemoryStream(); + + MiniSoftware.MiniWord.SaveAsByTemplate(memoryStream, templatePhyicalPath, testValue); + + memoryStream.Seek(0, SeekOrigin.Begin); + + + } + catch (Exception ) + { + + return ResponseOutput.NotOk("读取模板内容失败, 请将文件另存为docx格式尝试!"); + } + + + } + } + var entity = await _commonDocumentRepository.InsertOrUpdateAsync(addOrEditCommonDocument, true, verifyExp1); return ResponseOutput.Ok(entity.Id.ToString()); diff --git a/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs b/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs index f91d1b92..82ebf9fd 100644 --- a/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs +++ b/IRaCIS.Core.Application/Service/Document/DTO/TrialEmailNoticeConfigViewModel.cs @@ -27,8 +27,8 @@ namespace IRaCIS.Core.Application.ViewModel public List TrialEmailNoticeUserList { get; set; } - public new List ToUserIdList => TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(t => t.UserId).ToList(); - public new List CopyUserIdList => TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(t => t.UserId).ToList(); + public new List ToUserTypeList => TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(t => t.UserType).ToList(); + public new List CopyUserTypeList => TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(t => t.UserType).ToList(); } @@ -36,7 +36,6 @@ namespace IRaCIS.Core.Application.ViewModel public class EmailUserInfoDto { - public Guid UserId { get; set; } public Guid TrialEmailNoticeConfigId { get; set; } @@ -44,11 +43,8 @@ namespace IRaCIS.Core.Application.ViewModel public EmailUserType EmailUserType { get; set; } - public string Email { get; set; } - public string UserName { get; set; } - - public string RealName { get; set; } + public UserTypeEnum UserType { get; set; } } @@ -86,19 +82,8 @@ namespace IRaCIS.Core.Application.ViewModel public string FromEmail { get; set; } = string.Empty; - public List ToUserIdList { get; set; } - public List CopyUserIdList { get; set; } - - - - //public List ReceiveEmailList { get; set; } - //public List CopyEmailList { get; set; } - - //[JsonIgnore] - //public string ReceiveEmailsStr { get; set; } = string.Empty; - - //[JsonIgnore] - //public string CopyEmailsStr { get; set; } = string.Empty; + public List ToUserTypeList { get; set; } + public List CopyUserTypeList { get; set; } diff --git a/IRaCIS.Core.Application/Service/Document/Interface/ITrialEmailNoticeConfigService.cs b/IRaCIS.Core.Application/Service/Document/Interface/ITrialEmailNoticeConfigService.cs index 7acbf331..54ed5e74 100644 --- a/IRaCIS.Core.Application/Service/Document/Interface/ITrialEmailNoticeConfigService.cs +++ b/IRaCIS.Core.Application/Service/Document/Interface/ITrialEmailNoticeConfigService.cs @@ -5,6 +5,8 @@ //-------------------------------------------------------------------- using IRaCIS.Core.Application.ViewModel; +using IRaCIS.Core.Domain.Share; + namespace IRaCIS.Core.Application.Interfaces { /// @@ -20,6 +22,7 @@ namespace IRaCIS.Core.Application.Interfaces Task DeleteTrialEmailNoticeConfig(Guid trialEmailNoticeConfigId); - - } + Task BaseBusinessScenarioSendEmailAsync( Guid visitTaskId); + + } } diff --git a/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs b/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs index 85d077fe..6c5268b3 100644 --- a/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs +++ b/IRaCIS.Core.Application/Service/Document/TrialEmailNoticeConfigService.cs @@ -13,6 +13,7 @@ using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Application.Helper; using IRaCIS.Application.Contracts; using IRaCIS.Core.Infra.EFCore.Common; +using IRaCIS.Core.Application.Contracts; namespace IRaCIS.Core.Application.Service { @@ -71,95 +72,18 @@ namespace IRaCIS.Core.Application.Service /// /// 测试邮件 带附件 填充word --前端不需要用 /// - /// /// - /// - /// /// /// - public async Task FillWordTemplateAndEmailConfig(Guid trialId, Guid visitTaskId, Guid trialReadingCriterionId, CommonDocumentBusinessScenario businessScenarioEnum) - { - var criterionTypeEnum = await _repository.Where(t => t.TrialId == trialId && t.Id == trialReadingCriterionId).Select(t => t.CriterionType).FirstOrDefaultAsync(); - - - var emailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == trialId && t.CriterionTypeEnum == criterionTypeEnum && t.BusinessScenarioEnum == businessScenarioEnum) - .Include(t => t.TrialEmailNoticeUserList).ThenInclude(t => t.User).FirstOrDefaultAsync(); - - if (emailConfig == null) - { - throw new BusinessValidationFailedException("找不到该项目标准场景下邮件的配置"); - } - - //填充邮件基本配置 - - var sendEmailConfig = new SMTPEmailConfig(); - - foreach (var item in emailConfig.TrialEmailNoticeUserList) - { - - if (item.User.EMail.Contains("@") && !string.IsNullOrEmpty(item.User.EMail)) - { - switch (item.EmailUserType) - { - case EmailUserType.From: - sendEmailConfig.FromEmailAddress = new MimeKit.MailboxAddress(item.User.FullName, item.User.EMail); - - break; - case EmailUserType.To: - sendEmailConfig.ToMailAddressList.Add(new MimeKit.MailboxAddress(item.User.FullName, item.User.EMail)); - - break; - case EmailUserType.Copy: - sendEmailConfig.CopyToMailAddressList.Add(new MimeKit.MailboxAddress(item.User.FullName, item.User.EMail)); - - break; - - default: - break; - } - } - } - - - //邮件附件 - var path = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, emailConfig.FilePath); - - if (!File.Exists(path)) - { - throw new BusinessValidationFailedException("找不到该项目标准场景下邮件模板"); - } - - //邮件内容html - var isNeedSend = await FillWordTemplateAndSetEmailAsync(visitTaskId, sendEmailConfig, businessScenarioEnum, emailConfig.FilePath, path); - - - - - - - - await SendEmailHelper.SendEmailAsync(sendEmailConfig); - - } - - - - private async Task FillWordTemplateAndSetEmailAsync(Guid visitTaskId, SMTPEmailConfig sendEmailConfig, CommonDocumentBusinessScenario businessScenarioEnum, string fileName,string templatePath) + public async Task BaseBusinessScenarioSendEmailAsync(Guid visitTaskId) { - var isNeedSend = true; - var answer = "否"; + CommonDocumentBusinessScenario? businessScenarioEnum = null; - - var pathToFile = _hostEnvironment.WebRootPath - + Path.DirectorySeparatorChar.ToString() - + "EmailTemplate" - + Path.DirectorySeparatorChar.ToString() - + "SubjectEnrollConfirmOrPDProgress.html"; - - - var documentNeedBasicInfo = await _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => new + #region 任务关联的项目配置 标准信息及配置,subject 信息 + var taskInfo = await _visitTaskRepository.Where(t => t.Id == visitTaskId).Select(t => new { + t.Trial.ResearchProgramNo, t.Subject.TrialSite.TrialSiteCode, SubjectCode = t.Subject.Code, @@ -167,11 +91,12 @@ namespace IRaCIS.Core.Application.Service t.Trial.IsEnrollementQualificationConfirm, t.Trial.IsPDProgressView, - IsBaseline = t.SourceSubjectVisit.IsBaseLine, + VisitEarliestScanDate = t.SourceSubjectVisit.EarliestScanDate, VisitName = t.SourceSubjectVisit.VisitName, t.SourceSubjectVisit.IsFinalVisit, t.SourceSubjectVisit.PDState, + t.SourceSubjectVisit.IsEnrollmentConfirm, ModuleEarliestScanDate = t.ReadModule.SubjectVisit.EarliestScanDate, ModuleVisitName = t.ReadModule.SubjectVisit.VisitName, @@ -182,67 +107,174 @@ namespace IRaCIS.Core.Application.Service t.ReadingTaskState, t.ReadingCategory, t.SignTime, + //仲裁规则 + t.TrialReadingCriterion.ArbitrationRule, + //单双中 + t.TrialReadingCriterion.ReadingType, + //有序与否 + t.TrialReadingCriterion.IsReadingTaskViewInOrder, + + MoudulePDState = t.ReadModule.SubjectVisit.PDState, + t.TrialId, + IsBaseline = t.SourceSubjectVisit.IsBaseLine, + + + + t.TrialReadingCriterion.CriterionType, t.TrialReadingCriterionId, - t.TrialReadingCriterion.ArbitrationRule, - t.TrialReadingCriterion.ReadingType, - t.TrialReadingCriterion.IsReadingTaskViewInOrder, }).FirstNotNullAsync(); + #endregion - if (documentNeedBasicInfo.ReadingCategory == ReadingCategory.Visit || documentNeedBasicInfo.ReadingCategory == ReadingCategory.Judge || documentNeedBasicInfo.ReadingCategory == ReadingCategory.Global) + + #region 任务 -邮件场景区分 + + if (taskInfo.ReadingTaskState == ReadingTaskState.HaveSigned) { + //入组确认场景 + if (taskInfo.IsEnrollmentConfirm && taskInfo.IsEnrollementQualificationConfirm && taskInfo.IsBaseline) + { + businessScenarioEnum = CommonDocumentBusinessScenario.EnrollConfirmed; + + + } + //PD确认场景 + else if (taskInfo.IsPDProgressView && + (taskInfo.PDState == PDStateEnum.PDProgress && taskInfo.SourceSubjectVisitId != null) || + (taskInfo.SouceReadModuleId != null && taskInfo.MoudulePDState == PDStateEnum.PDProgress)) + { + businessScenarioEnum = CommonDocumentBusinessScenario.PDConfirmed; + } + else + { + return; + } } else { - //isNeedSend = false; - return false; + throw new BusinessValidationFailedException("进行邮件发送前,该任务必须已签名完成并已经触发完成相应的任务生成"); } - //入组确认仅在基线 - if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed && documentNeedBasicInfo.IsEnrollementQualificationConfirm && documentNeedBasicInfo.IsBaseline) + + + var emailConfig = await _trialEmailNoticeConfigRepository.Where(t => t.TrialId == taskInfo.TrialId && t.CriterionTypeEnum == taskInfo.CriterionType && t.BusinessScenarioEnum == businessScenarioEnum) + .Include(t => t.TrialEmailNoticeUserList).FirstOrDefaultAsync(); + + + if (emailConfig == null) + { + throw new BusinessValidationFailedException("找不到该项目标准场景下邮件的配置"); + } + + #endregion + + + #region 发收件人配置 + + var sendEmailConfig = new SMTPEmailConfig(); + + var toUserList = _repository.Where(t => t.TrialId == taskInfo.TrialId && emailConfig.TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.To).Select(c => c.UserType).Contains(t.User.UserTypeEnum)).Select(t => new { t.User.EMail, t.User.FullName }); + + var copyUserList = _repository.Where(t => t.TrialId == taskInfo.TrialId && emailConfig.TrialEmailNoticeUserList.Where(t => t.EmailUserType == EmailUserType.Copy).Select(c => c.UserType).Contains(t.User.UserTypeEnum)).Select(t => new { t.User.EMail, t.User.FullName }); + + + if (emailConfig.FromEmail.Contains("@") && !string.IsNullOrEmpty(emailConfig.FromEmail)) { - //如果其他阅片人已经做了,说明发送了入组确认报告,第二个人做完就不发送了 + sendEmailConfig.FromEmailAddress = new MimeKit.MailboxAddress(emailConfig.FromName, emailConfig.FromEmail); - if (await _visitTaskRepository.AnyAsync(t => t.SourceSubjectVisitId == documentNeedBasicInfo.SourceSubjectVisitId && t.TaskState == TaskState.Effect && t.IsAnalysisCreate == false && + //测试 + sendEmailConfig.ToMailAddressList.Add(new MimeKit.MailboxAddress("ddd", "872297557@qq.com")); + + } + else + { + throw new BusinessValidationFailedException("发件邮箱有误,请核实"); + } + + foreach (var item in toUserList) + { + + if (item.EMail.Contains("@") && !string.IsNullOrEmpty(item.EMail)) + { + + sendEmailConfig.ToMailAddressList.Add(new MimeKit.MailboxAddress(item.FullName, item.EMail)); + + } + } + foreach (var item in copyUserList) + { + + if (item.EMail.Contains("@") && !string.IsNullOrEmpty(item.EMail)) + { + + sendEmailConfig.CopyToMailAddressList.Add(new MimeKit.MailboxAddress(item.FullName, item.EMail)); + + } + } + #endregion + + + + + + + //邮件附件 + var path = FileStoreHelper.GetPhysicalFilePath(_hostEnvironment, emailConfig.FilePath); + + if (!File.Exists(path)) + { + throw new BusinessValidationFailedException("找不到该项目标准场景下邮件模板"); + } + + + var pathToFile = _hostEnvironment.WebRootPath + + Path.DirectorySeparatorChar.ToString() + + "EmailTemplate" + + Path.DirectorySeparatorChar.ToString() + + "SubjectEnrollConfirmOrPDProgress.html"; + + var answer = "否"; + var isNeedSend = true; + + if (businessScenarioEnum == CommonDocumentBusinessScenario.EnrollConfirmed) + { + //如果其他阅片人已经做了,说明发送了入组确认报告,第二个人做完就不发送了 + if (await _visitTaskRepository.AnyAsync(t => t.SourceSubjectVisitId == taskInfo.SourceSubjectVisitId && t.TaskState == TaskState.Effect && t.IsAnalysisCreate == false && t.Id != visitTaskId && t.ReadingTaskState == ReadingTaskState.HaveSigned)) { - //isNeedSend = false; - - return false; + isNeedSend = false; } - - sendEmailConfig.TopicDescription = "入组确认"; - - using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) + else { - var templateInfo = SourceReader.ReadToEnd(); + sendEmailConfig.TopicDescription = "入组确认"; + + using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) + { + var templateInfo = SourceReader.ReadToEnd(); - sendEmailConfig.HtmlBodyStr = string.Format(templateInfo, - $" 附件为入组确认报告,请查收 " - ); + sendEmailConfig.HtmlBodyStr = string.Format(templateInfo, + $" 附件为入组确认报告,请查收 " + ); + } + + + + if (await _repository.Where().AnyAsync(x => x.VisitTaskId == visitTaskId && x.Answer == TargetState.Exist.GetEnumInt() && + x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion)) + { + + answer = "是"; + } } - - - if (await _repository.Where().AnyAsync(x => x.VisitTaskId == visitTaskId && x.Answer == TargetState.Exist.GetEnumInt() && - x.ReadingTableQuestionTrial.QuestionMark == QuestionMark.State && x.ReadingQuestionTrial.LesionType == LesionType.TargetLesion)) - { - - answer = "是"; - - //修改Subject 状态 need to do - - } - - + } - else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed && documentNeedBasicInfo.IsPDProgressView) + else if (businessScenarioEnum == CommonDocumentBusinessScenario.PDConfirmed) { - sendEmailConfig.TopicDescription = "疾病进展"; using (StreamReader SourceReader = System.IO.File.OpenText(pathToFile)) @@ -257,16 +289,16 @@ namespace IRaCIS.Core.Application.Service //有序 - if (documentNeedBasicInfo.IsReadingTaskViewInOrder) + if (taskInfo.IsReadingTaskViewInOrder) { //单重 - if (documentNeedBasicInfo.ReadingType == ReadingMethod.Single) + if (taskInfo.ReadingType == ReadingMethod.Single) { //仲裁在访视上 或者在阅片期 - if (documentNeedBasicInfo.ArbitrationRule != ArbitrationRule.None) + if (taskInfo.ArbitrationRule != ArbitrationRule.None) { throw new BusinessValidationFailedException("单重有序阅片配置有误(不应该有仲裁对象配置),请核查!"); @@ -275,10 +307,10 @@ namespace IRaCIS.Core.Application.Service //要求PD 确认的访视 是截止访视 还是非截止访视(根据该访视有没有配置阅片期来判断) - if (documentNeedBasicInfo.ReadingCategory == ReadingCategory.Visit) + if (taskInfo.ReadingCategory == ReadingCategory.Visit) { //存在阅片期 那么就是截止访视 - if (await _repository.Where(t => t.TrialReadingCriterionId == documentNeedBasicInfo.TrialReadingCriterionId && t.SubjectVisitId == documentNeedBasicInfo.SourceSubjectVisitId && t.ReadingSetType == ReadingSetType.ImageReading).AnyAsync()) + if (await _repository.Where(t => t.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && t.SubjectVisitId == taskInfo.SourceSubjectVisitId && t.ReadingSetType == ReadingSetType.ImageReading).AnyAsync()) { isNeedSend = false; } @@ -287,7 +319,7 @@ namespace IRaCIS.Core.Application.Service answer = await TranslatePdStateAsync(visitTaskId, ReadingCategory.Visit); } } - else if (documentNeedBasicInfo.ReadingCategory == ReadingCategory.Global) + else if (taskInfo.ReadingCategory == ReadingCategory.Global) { answer = await TranslatePdStateAsync(visitTaskId, ReadingCategory.Global); } @@ -299,16 +331,16 @@ namespace IRaCIS.Core.Application.Service } //双重 - else if (documentNeedBasicInfo.ReadingType == ReadingMethod.Double) + else if (taskInfo.ReadingType == ReadingMethod.Double) { //仲裁在访视上 就没有全局阅片 没有阅片期 - if (documentNeedBasicInfo.ArbitrationRule == ArbitrationRule.Visit) + if (taskInfo.ArbitrationRule == ArbitrationRule.Visit) { //找到 访视,裁判 所有有效任务(不可能有全局的) 访视和裁判任务的SourceSubjectVisitId 一样 - var taskList = await _visitTaskRepository.Where(t => t.SourceSubjectVisitId == documentNeedBasicInfo.SourceSubjectVisitId && t.IsAnalysisCreate == false && t.TaskState == TaskState.Effect && - (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Judge )).ToListAsync(); + var taskList = await _visitTaskRepository.Where(t => t.SourceSubjectVisitId == taskInfo.SourceSubjectVisitId && t.IsAnalysisCreate == false && t.TaskState == TaskState.Effect && + (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Judge)).ToListAsync(); //这里要求 到这里已经如果有裁判 已经生成裁判了保存数据库 @@ -316,7 +348,7 @@ namespace IRaCIS.Core.Application.Service if (taskList.Count == 2 && taskList.Count(t => t.ReadingTaskState == ReadingTaskState.HaveSigned && t.ReadingCategory == ReadingCategory.Visit) == 2) { - answer = await TranslatePdStateAsync(visitTaskId, documentNeedBasicInfo.ReadingCategory); + answer = await TranslatePdStateAsync(visitTaskId, taskInfo.ReadingCategory); } //双人 产生裁判,并且裁判完成 发 else if (taskList.Count == 3 && taskList.Count(t => t.ReadingTaskState == ReadingTaskState.HaveSigned) == 3 && taskList.Where(t => t.ReadingCategory == ReadingCategory.Judge).Count() == 1) @@ -327,24 +359,23 @@ namespace IRaCIS.Core.Application.Service } else { - //isNeedSend = false; + isNeedSend = false; - return false; } - + } //在阅片期 仲裁在全局阅片,不会在访视上 - else if (documentNeedBasicInfo.ArbitrationRule == ArbitrationRule.Reading) + else if (taskInfo.ArbitrationRule == ArbitrationRule.Reading) { //是访视任务 不可能是裁判任务(访视上不会生成裁判),也不会是全局任务(全局任务 SourceSubjectVisitId=null ) - if (documentNeedBasicInfo.SourceSubjectVisitId != null) + if (taskInfo.SourceSubjectVisitId != null) { #region MyRegion ////看该访视是否是截止访视 - //var moduleIdList = await _repository.Where(t => t.TrialReadingCriterionId == documentNeedBasicInfo.TrialReadingCriterionId && t.SubjectVisitId == documentNeedBasicInfo.SourceSubjectVisitId && t.ReadingSetType == ReadingSetType.ImageReading) + //var moduleIdList = await _repository.Where(t => t.TrialReadingCriterionId == taskInfo.TrialReadingCriterionId && t.SubjectVisitId == taskInfo.SourceSubjectVisitId && t.ReadingSetType == ReadingSetType.ImageReading) // .Select(t => (Guid?) t.Id).ToListAsync(); ////截止访视 @@ -371,16 +402,16 @@ namespace IRaCIS.Core.Application.Service } //是全局任务 或者全局的裁判任务 (如果是全局任务,那么此时裁判任务已经生成,如果是全局裁判) - else if (documentNeedBasicInfo.SouceReadModuleId != null) + else if (taskInfo.SouceReadModuleId != null) { - var taskList = await _visitTaskRepository.Where(t => t.IsAnalysisCreate == false && t.TaskState == TaskState.Effect && t.SouceReadModuleId== documentNeedBasicInfo.SouceReadModuleId + var taskList = await _visitTaskRepository.Where(t => t.IsAnalysisCreate == false && t.TaskState == TaskState.Effect && t.SouceReadModuleId == taskInfo.SouceReadModuleId && (t.ReadingCategory == ReadingCategory.Global || t.ReadingCategory == ReadingCategory.Judge)).ToListAsync(); //两个全局没有裁判 if (taskList.Count == 2 && taskList.Count(t => t.ReadingTaskState == ReadingTaskState.HaveSigned && t.ReadingCategory == ReadingCategory.Global) == 2) { - answer = await TranslatePdStateAsync(visitTaskId, documentNeedBasicInfo.ReadingCategory); + answer = await TranslatePdStateAsync(visitTaskId, taskInfo.ReadingCategory); } //双人全局产生裁判 else if (taskList.Count == 3 && taskList.Count(t => t.ReadingTaskState == ReadingTaskState.HaveSigned) == 3 && taskList.Where(t => t.ReadingCategory == ReadingCategory.Judge).Count() == 1 && taskList.Where(t => t.ReadingCategory == ReadingCategory.Global).Count() == 2) @@ -391,9 +422,8 @@ namespace IRaCIS.Core.Application.Service } else { - //isNeedSend = false; + isNeedSend = false; - return false; } } @@ -420,22 +450,22 @@ namespace IRaCIS.Core.Application.Service //单重 - if (documentNeedBasicInfo.ReadingType == ReadingMethod.Single && documentNeedBasicInfo.ArbitrationRule == ArbitrationRule.None) + if (taskInfo.ReadingType == ReadingMethod.Single && taskInfo.ArbitrationRule == ArbitrationRule.None) { - answer = await TranslatePdStateAsync(visitTaskId, documentNeedBasicInfo.ReadingCategory); + answer = await TranslatePdStateAsync(visitTaskId, taskInfo.ReadingCategory); } //双重 截止访视只在阅片期的时候存在 要求PD确认的访视 肯定是非截止访视 - else if (documentNeedBasicInfo.ReadingType == ReadingMethod.Double && documentNeedBasicInfo.ArbitrationRule == ArbitrationRule.Visit) + else if (taskInfo.ReadingType == ReadingMethod.Double && taskInfo.ArbitrationRule == ArbitrationRule.Visit) { //在两位阅片人读完访视后,如果有裁判者等裁判读完,如果无裁判则等第二个人的读完 - var taskList = await _visitTaskRepository.Where(t => t.SourceSubjectVisitId == documentNeedBasicInfo.SourceSubjectVisitId && t.IsAnalysisCreate == false && t.TaskState == TaskState.Effect && (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Judge)).ToListAsync(); + var taskList = await _visitTaskRepository.Where(t => t.SourceSubjectVisitId == taskInfo.SourceSubjectVisitId && t.IsAnalysisCreate == false && t.TaskState == TaskState.Effect && (t.ReadingCategory == ReadingCategory.Visit || t.ReadingCategory == ReadingCategory.Judge)).ToListAsync(); //这里要求 到这里已经如果有裁判 已经生成裁判了保存数据库 if (taskList.Count == 2 && taskList.Count(t => t.ReadingTaskState == ReadingTaskState.HaveSigned && t.ReadingCategory == ReadingCategory.Visit) == 2) { - answer = await TranslatePdStateAsync(visitTaskId, documentNeedBasicInfo.ReadingCategory); + answer = await TranslatePdStateAsync(visitTaskId, taskInfo.ReadingCategory); } else if (taskList.Count == 3 && taskList.Count(t => t.ReadingTaskState == ReadingTaskState.HaveSigned) == 3 && taskList.Where(t => t.ReadingCategory == ReadingCategory.Judge).Count() == 1) { @@ -445,8 +475,7 @@ namespace IRaCIS.Core.Application.Service } else { - //isNeedSend = false; - return false; + isNeedSend = false; } } @@ -459,46 +488,49 @@ namespace IRaCIS.Core.Application.Service } } - + else + { + isNeedSend=false; + } if (isNeedSend) { - - var value = new Dictionary() { - ["SponsorName"] = documentNeedBasicInfo.SponsorName, - ["ResearchProgramNo"] = documentNeedBasicInfo.ResearchProgramNo, - ["TrialSiteCode"] = documentNeedBasicInfo.TrialSiteCode, - ["SubjectCode"] = documentNeedBasicInfo.SubjectCode, - ["VisitName"] = documentNeedBasicInfo.VisitName, - ["EarliestScanDate"] = documentNeedBasicInfo.SourceSubjectVisitId!=null? documentNeedBasicInfo.VisitEarliestScanDate: documentNeedBasicInfo.ModuleEarliestScanDate, - ["SignTime"] = documentNeedBasicInfo.SignTime, + ["SponsorName"] = taskInfo.SponsorName, + ["ResearchProgramNo"] = taskInfo.ResearchProgramNo, + ["TrialSiteCode"] = taskInfo.TrialSiteCode, + ["SubjectCode"] = taskInfo.SubjectCode, + ["VisitName"] = taskInfo.VisitName, + ["EarliestScanDate"] = taskInfo.SourceSubjectVisitId != null ? taskInfo.VisitEarliestScanDate : taskInfo.ModuleEarliestScanDate, + ["SignTime"] = taskInfo.SignTime, ["Result"] = answer }; MemoryStream memoryStream = new MemoryStream(); + MiniSoftware.MiniWord.SaveAsByTemplate(memoryStream, path, value); - MiniSoftware.MiniWord.SaveAsByTemplate(memoryStream, templatePath, value); + memoryStream.Seek(0, SeekOrigin.Begin); sendEmailConfig.EmailAttachMentConfigList.Add(new EmailAttachMentConfig() { - FileName = fileName, + FileName = emailConfig.FileName, FileStream = memoryStream }); - return false; - } - else - { - return false; + + await SendEmailHelper.SendEmailAsync(sendEmailConfig); + } + } + + private async Task TranslatePdStateAsync(Guid visitTaskId, ReadingCategory readingCategory) { @@ -551,12 +583,12 @@ namespace IRaCIS.Core.Application.Service /// /// /// - public async Task> GetTrialUserSelectList(Guid trialId) + public async Task> GetTrialUserTypeSelectList(Guid trialId) { - var query = _trialUserRepository.Where(t => t.TrialId == trialId && t.IsDeleted == false, false, true).IgnoreQueryFilters() + var query = _trialUserRepository.Where(t => t.TrialId == trialId && t.IsDeleted == false, false, true).IgnoreQueryFilters().Select(t => t.User.UserTypeRole) - .ProjectTo(_mapper.ConfigurationProvider); + .ProjectTo(_mapper.ConfigurationProvider); return await query.ToListAsync(); @@ -588,15 +620,15 @@ namespace IRaCIS.Core.Application.Service var entity = _mapper.Map(addOrEditTrialEmailNoticeConfig); - foreach (var item in addOrEditTrialEmailNoticeConfig.ToUserIdList) + foreach (var item in addOrEditTrialEmailNoticeConfig.ToUserTypeList) { - entity.TrialEmailNoticeUserList.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserId = item }); + entity.TrialEmailNoticeUserList.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = item }); } - foreach (var item in addOrEditTrialEmailNoticeConfig.CopyUserIdList) + foreach (var item in addOrEditTrialEmailNoticeConfig.CopyUserTypeList) { - entity.TrialEmailNoticeUserList.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserId = item }); + entity.TrialEmailNoticeUserList.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = item }); } @@ -619,15 +651,15 @@ namespace IRaCIS.Core.Application.Service List trialEmailNoticeUsers = new List(); - foreach (var item in addOrEditTrialEmailNoticeConfig.ToUserIdList) + foreach (var item in addOrEditTrialEmailNoticeConfig.ToUserTypeList) { - trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserId = item, TrialEmailNoticeConfigId = entity.Id }); + trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.To, UserType = item, TrialEmailNoticeConfigId = entity.Id }); } - foreach (var item in addOrEditTrialEmailNoticeConfig.CopyUserIdList) + foreach (var item in addOrEditTrialEmailNoticeConfig.CopyUserTypeList) { - trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserId = item, TrialEmailNoticeConfigId = entity.Id }); + trialEmailNoticeUsers.Add(new TrialEmailNoticeUser() { EmailUserType = EmailUserType.Copy, UserType = item, TrialEmailNoticeConfigId = entity.Id }); } await _repository.AddRangeAsync(trialEmailNoticeUsers); diff --git a/IRaCIS.Core.Application/Service/Document/_MapConfig.cs b/IRaCIS.Core.Application/Service/Document/_MapConfig.cs index 1ea6922d..d1c4f6b3 100644 --- a/IRaCIS.Core.Application/Service/Document/_MapConfig.cs +++ b/IRaCIS.Core.Application/Service/Document/_MapConfig.cs @@ -81,10 +81,7 @@ namespace IRaCIS.Core.Application.Service .ForMember(d => d.UserName, c => c.MapFrom(t => t.User.UserName)); - CreateMap() - .ForMember(d => d.Email, c => c.MapFrom(t => t.User.EMail)) - .ForMember(d => d.RealName, c => c.MapFrom(t => t.User.FullName)) - .ForMember(d => d.UserName, c => c.MapFrom(t => t.User.UserName)); + CreateMap(); } } diff --git a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingMedicineQuestionViewModel.cs b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingMedicineQuestionViewModel.cs index 6ce7ed21..e7f08410 100644 --- a/IRaCIS.Core.Application/Service/Reading/Dto/ReadingMedicineQuestionViewModel.cs +++ b/IRaCIS.Core.Application/Service/Reading/Dto/ReadingMedicineQuestionViewModel.cs @@ -17,7 +17,7 @@ namespace IRaCIS.Core.Application.ViewModel } ///ReadingMedicineSystemQuestionQuery 列表查询参数模型 - public class ReadingMedicineSystemQuestionQuery + public class ReadingMedicineSystemQuestionQuery:PageInput { public string Type { get; set; } = string.Empty; public string ParentTriggerValue { get; set; } = string.Empty; diff --git a/IRaCIS.Core.Application/Service/Reading/MedicalAudit/ReadingMedicineQuestionService.cs b/IRaCIS.Core.Application/Service/Reading/MedicalAudit/ReadingMedicineQuestionService.cs index f0b70b0e..64fe6ee8 100644 --- a/IRaCIS.Core.Application/Service/Reading/MedicalAudit/ReadingMedicineQuestionService.cs +++ b/IRaCIS.Core.Application/Service/Reading/MedicalAudit/ReadingMedicineQuestionService.cs @@ -43,7 +43,7 @@ namespace IRaCIS.Core.Application.Service /// /// [HttpPost] - public async Task> GetReadingMedicineSystemQuestionList(ReadingMedicineSystemQuestionQuery inDto) + public async Task> GetReadingMedicineSystemQuestionList(ReadingMedicineSystemQuestionQuery inDto) { //避免前端遍历 var criterionEnum = inDto.TrialReadingCriterionId != null ? _readingQuestionCriterionTrialRepository.Where(t => t.Id == inDto.TrialReadingCriterionId).Select(t => t.CriterionType).FirstOrDefault(): CriterionType.NoCriterion; @@ -57,7 +57,8 @@ namespace IRaCIS.Core.Application.Service .WhereIf(inDto.CriterionEnum != null, x => x.CriterionEnumStr.Contains($"|{inDto.CriterionEnum}|") ) .WhereIf(inDto.TrialReadingCriterionId != null, x => x.CriterionEnumStr.Contains($"|{criterionEnum}|")) .ProjectTo(_mapper.ConfigurationProvider).OrderBy(x => x.ShowOrder); - return await query.ToListAsync(); + + return await query.ToPagedListAsync(inDto.PageIndex, inDto.PageSize,inDto.SortField,inDto.Asc); } /// diff --git a/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs b/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs index aec3342b..9e6d8e60 100644 --- a/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs +++ b/IRaCIS.Core.Application/Service/Reading/ReadingImageTask/ReadingImageTaskService.cs @@ -9,6 +9,7 @@ using IRaCIS.Core.Application.Contracts; using IRaCIS.Core.Infrastructure; using IRaCIS.Core.Application.Service; using IRaCIS.Core.Application.ViewModel; +using IRaCIS.Core.Application.Interfaces; namespace IRaCIS.Application.Services { @@ -45,6 +46,8 @@ namespace IRaCIS.Application.Services private readonly IRepository _readingQuestionSystem; private readonly IRepository _readingQuestionTrialRepository; + private readonly ITrialEmailNoticeConfigService _trialEmailNoticeConfigService; + public ReadingImageTaskService( IMapper mapper, @@ -72,7 +75,9 @@ namespace IRaCIS.Application.Services IRepository readingQuestionCriterionTrialRepository, IRepository readingQuestionCriterionSystemRepository, IRepository ReadingQuestionSystem, - IRepository readingQuestionTrialRepository + IRepository readingQuestionTrialRepository, + + ITrialEmailNoticeConfigService trialEmailNoticeConfigService ) { base._mapper = mapper; @@ -101,6 +106,8 @@ namespace IRaCIS.Application.Services this._readingQuestionCriterionSystemRepository = readingQuestionCriterionSystemRepository; this._readingQuestionSystem = ReadingQuestionSystem; this._readingQuestionTrialRepository = readingQuestionTrialRepository; + + _trialEmailNoticeConfigService = trialEmailNoticeConfigService; } @@ -135,10 +142,10 @@ namespace IRaCIS.Application.Services [HttpPost] public async Task<(List, object)> GetRelatedVisitTask(GetRelatedVisitTaskInDto inDto) { - var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x=>x.TrialReadingCriterion).FirstNotNullAsync(); + var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).Include(x => x.TrialReadingCriterion).FirstNotNullAsync(); var baselineVisitId = await _subjectVisitRepository.Where(x => x.SubjectId == taskInfo.SubjectId && x.IsBaseLine && !x.IsLostVisit).Select(x => x.Id).FirstNotNullAsync(); var result = await _visitTaskRepository - .WhereIf(taskInfo.TaskState != TaskState.Effect,x=>x.Id== inDto.VisitTaskId) + .WhereIf(taskInfo.TaskState != TaskState.Effect, x => x.Id == inDto.VisitTaskId) .Where(x => (x.TrialId == taskInfo.TrialId && x.SubjectId == taskInfo.SubjectId && @@ -338,7 +345,181 @@ namespace IRaCIS.Application.Services [HttpPost] public async Task GetReadingReportEvaluation(GetReadingReportEvaluationInDto indto) { - return await _readingCalculateService.GetReadingReportEvaluation(indto); + + + GetReadingReportEvaluationOutDto result = new GetReadingReportEvaluationOutDto(); + + result.CalculateResult = await _readingCalculateService.GetReportVerify(new GetReportVerifyInDto() + { + VisitTaskId = indto.VisitTaskId + }); + + var visitTaskInfo = await _visitTaskRepository.Where(x => x.Id == indto.VisitTaskId).FirstNotNullAsync(); + + //if (visitTaskInfo.TaskState != TaskState.Effect) + //{ + // throw new BusinessValidationFailedException($"当前任务已失效!"); + //} + result.ReadingTaskState = visitTaskInfo.ReadingTaskState; + var taskInfoList = await _visitTaskRepository + // 失效的只查看自己 + .WhereIf(visitTaskInfo.TaskState != TaskState.Effect, x => x.Id == indto.VisitTaskId) + .Where(x => (x.SubjectId == visitTaskInfo.SubjectId && x.TaskState == TaskState.Effect + && x.IsAnalysisCreate == visitTaskInfo.IsAnalysisCreate + && x.IsSelfAnalysis == visitTaskInfo.IsSelfAnalysis + && x.ArmEnum == visitTaskInfo.ArmEnum + && x.TrialReadingCriterionId == visitTaskInfo.TrialReadingCriterionId + && x.ReadingCategory == ReadingCategory.Visit && !x.IsAnalysisCreate && x.ReadingTaskState == ReadingTaskState.HaveSigned) || x.Id == indto.VisitTaskId + ).OrderBy(x => x.VisitTaskNum).Select(x => new VisitTaskInfo() + { + BlindName = x.SourceSubjectVisit.BlindName, + IsBaseLine = x.SourceSubjectVisit.IsBaseLine, + VisitTaskId = x.Id, + TaskName = x.TaskName, + VisitTaskNum = x.VisitTaskNum, + IsCurrentTask = x.Id == indto.VisitTaskId, + + }).ToListAsync(); + + result.VisitTaskList = taskInfoList; + + var visitTaskIds = taskInfoList.Select(x => x.VisitTaskId).ToList(); + + var criterionId = visitTaskInfo.TrialReadingCriterionId; + var questionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == criterionId).ToListAsync(); + var tableQuestionList = await _readingTableQuestionTrialRepository.Where(x => x.TrialCriterionId == criterionId).OrderBy(x => x.ShowOrder).ToListAsync(); + var tableAnsweRowInfos = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == indto.VisitTaskId).ProjectTo(_mapper.ConfigurationProvider).ToListAsync(); + + var answers = await _readingTaskQuestionAnswerRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId)).ToListAsync(); + var tableAnswers = await _readingTableQuestionAnswerRepository.Where(x => visitTaskIds.Contains(x.VisitTaskId)).ToListAsync(); + + + // 第一级 + + #region 构造问题 + List questions = questionList.Where(x => x.Type == ReadingQestionType.Group).OrderBy(x => x.ShowOrder).Select(x => new ReadingReportDto() + { + QuestionId = x.Id, + GroupName = x.GroupName, + IsShowInDicom = x.IsShowInDicom, + Type = x.Type, + QuestionType = x.QuestionType, + LesionType = x.LesionType, + QuestionGenre = x.QuestionGenre, + DictionaryCode = x.DictionaryCode, + TypeValue = x.TypeValue, + QuestionName = x.QuestionName, + ShowOrder = x.ShowOrder, + ValueType = x.ValueType, + Unit = x.Unit, + + }).ToList(); + + // 分组 + foreach (var item in questions) + { + item.Childrens = questionList.Where(x => x.GroupName == item.GroupName && x.Type != ReadingQestionType.Group).OrderBy(x => x.ShowOrder).Select(x => new ReadingReportDto() + { + GroupName = x.GroupName, + QuestionId = x.Id, + IsShowInDicom = x.IsShowInDicom, + QuestionName = x.QuestionName, + LesionType = x.LesionType, + QuestionGenre = x.QuestionGenre, + DictionaryCode = x.DictionaryCode, + Type = x.Type, + QuestionType = x.QuestionType, + TypeValue = x.TypeValue, + ShowOrder = x.ShowOrder, + OrderMark = x.OrderMark, + ValueType = x.ValueType, + Unit = x.Unit, + + }).ToList(); + + // 问题 + foreach (var question in item.Childrens) + { + + foreach (var task in taskInfoList) + { + + question.Answer.Add(new TaskQuestionAnswer() + { + Answer = answers.Where(x => x.VisitTaskId == task.VisitTaskId && x.ReadingQuestionTrialId == question.QuestionId).Select(x => x.Answer).FirstIsNullReturnEmpty(), + TaskName = task.TaskName, + VisitTaskId = task.VisitTaskId, + }); + } + + // 构造表格行数据 + + + var rowlist = tableAnsweRowInfos.Where(x => x.QuestionId == question.QuestionId).OrderBy(x => x.RowIndex).ToList(); + + + question.Childrens = rowlist.Select(x => new ReadingReportDto() + { + QuestionName = question.OrderMark + x.RowIndex.GetLesionMark(), + SplitOrMergeLesionName = x.MergeName.IsNullOrEmpty() ? x.SplitName : x.MergeName, + SplitOrMergeType = x.SplitOrMergeType, + LesionType = question.LesionType, + IsCanEditPosition = x.IsCanEditPosition, + RowIndex = x.RowIndex, + }).ToList(); + + + foreach (var row in question.Childrens) + { + // tableQuestion + row.Childrens = tableQuestionList.Where(x => x.ReadingQuestionId == question.QuestionId).Select(x => new ReadingReportDto() + { + QuestionName = x.QuestionName, + QuestionId = x.ReadingQuestionId, + TableQuestionId = x.Id, + Type = x.Type, + LesionType = question.LesionType, + TableQuestionType = x.TableQuestionType, + DictionaryCode = x.DictionaryCode, + QuestionMark = x.QuestionMark, + TypeValue = x.TypeValue, + RowIndex = row.RowIndex, + ShowOrder = x.ShowOrder, + ValueType = x.ValueType, + Unit = x.Unit, + }).ToList(); + + + foreach (var tableQuestion in row.Childrens) + { + foreach (var task in taskInfoList) + { + + tableQuestion.Answer.Add(new TaskQuestionAnswer() + { + Answer = tableAnswers.Where(x => x.VisitTaskId == task.VisitTaskId && x.QuestionId == tableQuestion.QuestionId && x.RowIndex == tableQuestion.RowIndex && x.TableQuestionId == tableQuestion.TableQuestionId).Select(x => x.Answer).FirstIsNullReturnEmpty(), + TaskName = task.TaskName, + VisitTaskId = task.VisitTaskId, + }); + } + } + + + } + + + }; + } + #endregion + + + + result.TaskQuestions = questions; + + + + return result; + } /// @@ -475,7 +656,7 @@ namespace IRaCIS.Application.Services { readingTaskState = visitTaskInfo.ReadingTaskState, FormType = formType, - TaskNum= visitTaskInfo.VisitTaskNum, + TaskNum = visitTaskInfo.VisitTaskNum, }); ; } @@ -502,7 +683,7 @@ namespace IRaCIS.Application.Services ShowOrder = x.ShowOrder, GroupName = string.Empty, Id = x.Id, - DictionaryCode=x.DictionaryCode, + DictionaryCode = x.DictionaryCode, Type = x.Type, TableQuestionType = x.TableQuestionType, DependParentId = x.DependParentId, @@ -518,8 +699,8 @@ namespace IRaCIS.Application.Services QuestionName = x.QuestionName, RelationQuestions = new List(), Remark = x.Remark, - ValueType=x.ValueType, - Unit=x.Unit, + ValueType = x.ValueType, + Unit = x.Unit, }).ToList(); }); var thisAnswer = tableAnswers.Where(x => x.QuestionId == item.Id).ToList(); @@ -536,8 +717,6 @@ namespace IRaCIS.Application.Services var rowInfo = tableAnsweRowInfos.Where(y => y.RowIndex == x && y.QuestionId == item.Id).FirstOrDefault(); - answers.Add("BlindName", rowInfo.BlindName); - answers.Add("IsDicomReading", rowInfo.IsDicomReading.ToString()); answers.Add("MeasureData", rowInfo == null ? string.Empty : rowInfo.MeasureData); answers.Add("RowIndex", x.ToString()); answers.Add("RowId", rowInfo.Id.ToString()); @@ -546,8 +725,8 @@ namespace IRaCIS.Application.Services answers.Add("InstanceId", rowInfo == null ? string.Empty : rowInfo.InstanceId.ToString()); answers.Add("SeriesId", rowInfo == null ? string.Empty : rowInfo.SeriesId.ToString()); answers.Add("IsCurrentTaskAdd", rowInfo == null ? false.ToString() : rowInfo.IsCurrentTaskAdd.ToString()); - answers.Add("SplitOrMergeLesionName",rowInfo.SplitName.IsNullOrEmpty()? rowInfo.MergeName: rowInfo.SplitName); - answers.Add("SplitOrMergeType", rowInfo.SplitOrMergeType==null?string.Empty:((int)rowInfo.SplitOrMergeType).ToString()); + answers.Add("SplitOrMergeLesionName", rowInfo.SplitName.IsNullOrEmpty() ? rowInfo.MergeName : rowInfo.SplitName); + answers.Add("SplitOrMergeType", rowInfo.SplitOrMergeType == null ? string.Empty : ((int)rowInfo.SplitOrMergeType).ToString()); item.TableQuestions.Answers.Add(answers); @@ -715,7 +894,7 @@ namespace IRaCIS.Application.Services public async Task DeleteReadingRowAnswer(DeleteReadingRowAnswerInDto inDto) { - var deleteRowInfo = await _readingTableAnswerRowInfoRepository.Where(x =>x.Id== inDto.RowId).FirstNotNullAsync(); + var deleteRowInfo = await _readingTableAnswerRowInfoRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == inDto.RowIndex && x.QuestionId == inDto.QuestionId).FirstNotNullAsync(); if (deleteRowInfo == null) { return ResponseOutput.Ok(true); @@ -727,8 +906,8 @@ namespace IRaCIS.Application.Services throw new BusinessValidationFailedException($"当前病灶分裂出其他病灶或者其他病灶合并到了当前病灶,删除失败"); } - await _readingTableQuestionAnswerRepository.DeleteFromQueryAsync(x => x.RowId== inDto.RowId); - await _readingTableAnswerRowInfoRepository.DeleteFromQueryAsync(x => x.Id==inDto.RowId); + await _readingTableQuestionAnswerRepository.DeleteFromQueryAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == inDto.RowIndex && x.QuestionId == inDto.QuestionId); + await _readingTableAnswerRowInfoRepository.DeleteFromQueryAsync(x => x.VisitTaskId == inDto.VisitTaskId && x.RowIndex == inDto.RowIndex && x.QuestionId == inDto.QuestionId); await _readingTableAnswerRowInfoRepository.SaveChangesAsync(); @@ -855,8 +1034,6 @@ namespace IRaCIS.Application.Services rowInfo.TrialId = inDto.TrialId; rowInfo.QuestionId = inDto.QuestionId; rowInfo.MeasureData = inDto.MeasureData; - rowInfo.BlindName = inDto.BlindName; - rowInfo.IsDicomReading = inDto.IsDicomReading; rowInfo.IsCurrentTaskAdd = isCurrentTaskAdd; rowInfo.FristAddTaskNum = inDto.FristAddTaskNum; rowInfo.RowIndex = inDto.RowIndex; @@ -993,16 +1170,16 @@ namespace IRaCIS.Application.Services var taskInfo = await _visitTaskRepository.Where(x => x.Id == inDto.VisitTaskId).FirstNotNullAsync(); var readingQuestionList = await _readingQuestionTrialRepository.Where(x => x.ReadingQuestionCriterionTrialId == taskInfo.TrialReadingCriterionId - &&(x.IsJudgeQuestion||x.IsRequired== IsRequired.Required) + && (x.IsJudgeQuestion || x.IsRequired == IsRequired.Required) ).ToListAsync(); var answerQuestionIds = await _readingTaskQuestionAnswerRepository.Where(x => x.VisitTaskId == inDto.VisitTaskId).Select(x => x.ReadingQuestionTrialId).ToListAsync(); readingQuestionList = readingQuestionList.Where(x => !answerQuestionIds.Contains(x.Id)).ToList(); - if(readingQuestionList.Count()>0) + if (readingQuestionList.Count() > 0) { - throw new BusinessValidationFailedException($" 必填问题{ string.Join(',', readingQuestionList.Select(x =>x.QuestionName))}的答案为空或未保存"); + throw new BusinessValidationFailedException($" 必填问题{string.Join(',', readingQuestionList.Select(x => x.QuestionName))}的答案为空或未保存"); } await _readingCalculateService.VerifyVisitTaskQuestions(inDto); @@ -1199,6 +1376,18 @@ namespace IRaCIS.Application.Services await _visitTaskRepository.SaveChangesAsync(); + + + //基于业务场景发送邮件 + + //await _trialEmailNoticeConfigService.BaseBusinessScenarioSendEmailAsync( visitTaskId); + + + + + + + } @@ -1267,7 +1456,7 @@ namespace IRaCIS.Application.Services await AddOncologyTask(oncologyReadId); } - + break; } } diff --git a/IRaCIS.Core.Domain.Share/Common/EmailScenarioEnum.cs b/IRaCIS.Core.Domain.Share/Common/EmailScenarioEnum.cs index ff9a048e..d14ccc54 100644 --- a/IRaCIS.Core.Domain.Share/Common/EmailScenarioEnum.cs +++ b/IRaCIS.Core.Domain.Share/Common/EmailScenarioEnum.cs @@ -49,6 +49,8 @@ namespace IRaCIS.Core.Domain.Share public enum EmailUserType { + + //变为手动输入了,这里不需要了 From =1, To=2, diff --git a/IRaCIS.Core.Domain/Document/TrialEmailNoticeUser.cs b/IRaCIS.Core.Domain/Document/TrialEmailNoticeUser.cs index eb79b29e..cf8844ad 100644 --- a/IRaCIS.Core.Domain/Document/TrialEmailNoticeUser.cs +++ b/IRaCIS.Core.Domain/Document/TrialEmailNoticeUser.cs @@ -16,14 +16,12 @@ namespace IRaCIS.Core.Domain.Models public class TrialEmailNoticeUser : Entity { - [JsonIgnore] - public User User { get; set; } [JsonIgnore] public TrialEmailNoticeConfig TrialEmailNoticeConfig { get; set; } - public Guid UserId { get; set; } + public UserTypeEnum UserType { get; set; } public Guid TrialEmailNoticeConfigId { get; set; } diff --git a/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj b/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj index bd48e5c4..3b997b0f 100644 --- a/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj +++ b/IRaCIS.Core.Domain/IRaCIS.Core.Domain.csproj @@ -11,8 +11,8 @@ - - + + diff --git a/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj b/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj index d68ade0d..9f08fd7a 100644 --- a/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj +++ b/IRaCIS.Core.Infra.EFCore/IRaCIS.Core.Infra.EFCore.csproj @@ -19,7 +19,7 @@ - + diff --git a/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj b/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj index efe831ae..15269379 100644 --- a/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj +++ b/IRaCIS.Core.Infrastructure/IRaCIS.Core.Infrastructure.csproj @@ -9,10 +9,10 @@ - + - + diff --git a/IRaCISData/新建 DOCX 文档.docx b/IRaCISData/新建 DOCX 文档.docx deleted file mode 100644 index 6fb74f259242ded3990b31a083f898414413667d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10114 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